install: Add EXCLUDE_FROM_ALL option (#14921)

Let us take an example of a project that has some tests in a component
that need to be installed into a dedicated test package.  The user
expectation is that the result could be achieved by typing the
following:

    make
    make tests
    make install
    DESTDIR=/testpkgs make install-tests

However this results in test components in the default installation as
well as the testpkg.

Add an EXCLUDE_FROM_ALL option to the install() command to tell it that
the installation rule should not be included unless its component is
explicitly specified for installation.
This commit is contained in:
Nick Lewis 2016-02-01 10:01:39 +00:00 committed by Brad King
parent bfd1b3aaba
commit 18ce97c4a2
19 changed files with 113 additions and 41 deletions

View File

@ -45,11 +45,15 @@ signatures that specify them. The common options are:
is associated, such as "runtime" or "development". During is associated, such as "runtime" or "development". During
component-specific installation only install rules associated with component-specific installation only install rules associated with
the given component name will be executed. During a full installation the given component name will be executed. During a full installation
all components are installed. If ``COMPONENT`` is not provided a all components are installed unless marked with ``EXCLUDE_FROM_ALL``.
default component "Unspecified" is created. The default component If ``COMPONENT`` is not provided a default component "Unspecified" is
name may be controlled with the created. The default component name may be controlled with the
:variable:`CMAKE_INSTALL_DEFAULT_COMPONENT_NAME` variable. :variable:`CMAKE_INSTALL_DEFAULT_COMPONENT_NAME` variable.
``EXCLUDE_FROM_ALL``
Specify that the file is excluded from a full installation and only
installed as part of a component-specific installation
``RENAME`` ``RENAME``
Specify a name for an installed file that may be different from the Specify a name for an installed file that may be different from the
original file. Renaming is allowed only when a single file is original file. Renaming is allowed only when a single file is
@ -76,7 +80,8 @@ Installing Targets
[PERMISSIONS permissions...] [PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]] [CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>] [COMPONENT <component>]
[OPTIONAL] [NAMELINK_ONLY|NAMELINK_SKIP] [OPTIONAL] [EXCLUDE_FROM_ALL]
[NAMELINK_ONLY|NAMELINK_SKIP]
] [...]) ] [...])
The ``TARGETS`` form specifies rules for installing targets from a The ``TARGETS`` form specifies rules for installing targets from a
@ -172,7 +177,7 @@ Installing Files
[PERMISSIONS permissions...] [PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]] [CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>] [COMPONENT <component>]
[RENAME <name>] [OPTIONAL]) [RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])
The ``FILES`` form specifies rules for installing files for a project. The ``FILES`` form specifies rules for installing files for a project.
File names given as relative paths are interpreted with respect to the File names given as relative paths are interpreted with respect to the
@ -206,7 +211,8 @@ Installing Directories
[DIRECTORY_PERMISSIONS permissions...] [DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER] [USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
[CONFIGURATIONS [Debug|Release|...]] [CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>] [FILES_MATCHING] [COMPONENT <component>] [EXCLUDE_FROM_ALL]
[FILES_MATCHING]
[[PATTERN <pattern> | REGEX <regex>] [[PATTERN <pattern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS permissions...]] [...]) [EXCLUDE] [PERMISSIONS permissions...]] [...])
@ -282,7 +288,7 @@ Custom Installation Logic
:: ::
install([[SCRIPT <file>] [CODE <code>]] install([[SCRIPT <file>] [CODE <code>]]
[COMPONENT <component>] [...]) [COMPONENT <component>] [EXCLUDE_FROM_ALL] [...])
The ``SCRIPT`` form will invoke the given CMake script files during The ``SCRIPT`` form will invoke the given CMake script files during
installation. If the script file name is a relative path it will be installation. If the script file name is a relative path it will be
@ -307,7 +313,8 @@ Installing Exports
[PERMISSIONS permissions...] [PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]] [CONFIGURATIONS [Debug|Release|...]]
[EXPORT_LINK_INTERFACE_LIBRARIES] [EXPORT_LINK_INTERFACE_LIBRARIES]
[COMPONENT <component>]) [COMPONENT <component>]
[EXCLUDE_FROM_ALL])
The ``EXPORT`` form generates and installs a CMake file containing code to The ``EXPORT`` form generates and installs a CMake file containing code to
import targets from the installation tree into another project. import targets from the installation tree into another project.

View File

@ -33,6 +33,7 @@ static cmInstallTargetGenerator* CreateInstallTargetGenerator(cmTarget& target,
impLib, args.GetPermissions().c_str(), impLib, args.GetPermissions().c_str(),
args.GetConfigurations(), args.GetComponent().c_str(), args.GetConfigurations(), args.GetComponent().c_str(),
message, message,
args.GetExcludeFromAll(),
args.GetOptional() || forceOpt); args.GetOptional() || forceOpt);
} }
@ -48,7 +49,8 @@ static cmInstallFilesGenerator* CreateInstallFilesGenerator(
programs, args.GetPermissions().c_str(), programs, args.GetPermissions().c_str(),
args.GetConfigurations(), args.GetComponent().c_str(), args.GetConfigurations(), args.GetComponent().c_str(),
message, message,
args.GetRename().c_str(), args.GetOptional()); args.GetExcludeFromAll(), args.GetRename().c_str(),
args.GetOptional());
} }
@ -117,6 +119,7 @@ bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args)
int componentCount = 0; int componentCount = 0;
bool doing_script = false; bool doing_script = false;
bool doing_code = false; bool doing_code = false;
bool exclude_from_all = false;
// Scan the args once for COMPONENT. Only allow one. // Scan the args once for COMPONENT. Only allow one.
// //
@ -128,6 +131,10 @@ bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args)
++i; ++i;
component = args[i]; component = args[i];
} }
if(args[i] == "EXCLUDE_FROM_ALL")
{
exclude_from_all = true;
}
} }
if(componentCount>1) if(componentCount>1)
@ -175,7 +182,7 @@ bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args)
} }
this->Makefile->AddInstallGenerator( this->Makefile->AddInstallGenerator(
new cmInstallScriptGenerator(script.c_str(), false, new cmInstallScriptGenerator(script.c_str(), false,
component.c_str())); component.c_str(), exclude_from_all));
} }
else if(doing_code) else if(doing_code)
{ {
@ -183,7 +190,7 @@ bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args)
std::string code = args[i]; std::string code = args[i];
this->Makefile->AddInstallGenerator( this->Makefile->AddInstallGenerator(
new cmInstallScriptGenerator(code.c_str(), true, new cmInstallScriptGenerator(code.c_str(), true,
component.c_str())); component.c_str(), exclude_from_all));
} }
} }
@ -949,6 +956,7 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
Doing doing = DoingDirs; Doing doing = DoingDirs;
bool in_match_mode = false; bool in_match_mode = false;
bool optional = false; bool optional = false;
bool exclude_from_all = false;
bool message_never = false; bool message_never = false;
std::vector<std::string> dirs; std::vector<std::string> dirs;
const char* destination = 0; const char* destination = 0;
@ -1130,6 +1138,19 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
// Switch to setting the component property. // Switch to setting the component property.
doing = DoingComponent; doing = DoingComponent;
} }
else if(args[i] == "EXCLUDE_FROM_ALL")
{
if(in_match_mode)
{
std::ostringstream e;
e << args[0] << " does not allow \""
<< args[i] << "\" after PATTERN or REGEX.";
this->SetError(e.str().c_str());
return false;
}
exclude_from_all = true;
doing = DoingNone;
}
else if(doing == DoingDirs) else if(doing == DoingDirs)
{ {
// Convert this directory to a full path. // Convert this directory to a full path.
@ -1273,6 +1294,7 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
configurations, configurations,
component.c_str(), component.c_str(),
message, message,
exclude_from_all,
literal_args.c_str(), literal_args.c_str(),
optional)); optional));
@ -1401,7 +1423,8 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
exportSet, exportSet,
ica.GetDestination().c_str(), ica.GetDestination().c_str(),
ica.GetPermissions().c_str(), ica.GetConfigurations(), ica.GetPermissions().c_str(), ica.GetConfigurations(),
ica.GetComponent().c_str(), message, fname.c_str(), ica.GetComponent().c_str(), message,
ica.GetExcludeFromAll(), fname.c_str(),
name_space.GetCString(), exportOld.IsEnabled()); name_space.GetCString(), exportOld.IsEnabled());
this->Makefile->AddInstallGenerator(exportGenerator); this->Makefile->AddInstallGenerator(exportGenerator);

View File

@ -29,9 +29,10 @@ cmInstallCommandArguments::cmInstallCommandArguments(
,ArgumentGroup() ,ArgumentGroup()
,Destination (&Parser, "DESTINATION" , &ArgumentGroup) ,Destination (&Parser, "DESTINATION" , &ArgumentGroup)
,Component (&Parser, "COMPONENT" , &ArgumentGroup) ,Component (&Parser, "COMPONENT" , &ArgumentGroup)
,ExcludeFromAll(&Parser, "EXCLUDE_FROM_ALL", &ArgumentGroup)
,Rename (&Parser, "RENAME" , &ArgumentGroup) ,Rename (&Parser, "RENAME" , &ArgumentGroup)
,Permissions (&Parser, "PERMISSIONS" , &ArgumentGroup) ,Permissions (&Parser, "PERMISSIONS" , &ArgumentGroup)
,Configurations(&Parser, "CONFIGURATIONS", &ArgumentGroup) ,Configurations(&Parser, "CONFIGURATIONS" , &ArgumentGroup)
,Optional (&Parser, "OPTIONAL" , &ArgumentGroup) ,Optional (&Parser, "OPTIONAL" , &ArgumentGroup)
,NamelinkOnly (&Parser, "NAMELINK_ONLY" , &ArgumentGroup) ,NamelinkOnly (&Parser, "NAMELINK_ONLY" , &ArgumentGroup)
,NamelinkSkip (&Parser, "NAMELINK_SKIP" , &ArgumentGroup) ,NamelinkSkip (&Parser, "NAMELINK_SKIP" , &ArgumentGroup)
@ -110,6 +111,19 @@ bool cmInstallCommandArguments::GetOptional() const
return false; return false;
} }
bool cmInstallCommandArguments::GetExcludeFromAll() const
{
if (this->ExcludeFromAll.IsEnabled())
{
return true;
}
if (this->GenericArguments!=0)
{
return this->GenericArguments->GetExcludeFromAll();
}
return false;
}
bool cmInstallCommandArguments::GetNamelinkOnly() const bool cmInstallCommandArguments::GetNamelinkOnly() const
{ {
if (this->NamelinkOnly.IsEnabled()) if (this->NamelinkOnly.IsEnabled())

View File

@ -30,6 +30,7 @@ class cmInstallCommandArguments
const std::string& GetDestination() const; const std::string& GetDestination() const;
const std::string& GetComponent() const; const std::string& GetComponent() const;
bool GetExcludeFromAll() const;
const std::string& GetRename() const; const std::string& GetRename() const;
const std::string& GetPermissions() const; const std::string& GetPermissions() const;
const std::vector<std::string>& GetConfigurations() const; const std::vector<std::string>& GetConfigurations() const;
@ -48,6 +49,7 @@ class cmInstallCommandArguments
cmInstallCommandArguments(); // disabled cmInstallCommandArguments(); // disabled
cmCAString Destination; cmCAString Destination;
cmCAString Component; cmCAString Component;
cmCAEnabler ExcludeFromAll;
cmCAString Rename; cmCAString Rename;
cmCAStringVector Permissions; cmCAStringVector Permissions;
cmCAStringVector Configurations; cmCAStringVector Configurations;

View File

@ -23,9 +23,11 @@ cmInstallDirectoryGenerator
std::vector<std::string> const& configurations, std::vector<std::string> const& configurations,
const char* component, const char* component,
MessageLevel message, MessageLevel message,
bool exclude_from_all,
const char* literal_args, const char* literal_args,
bool optional): bool optional):
cmInstallGenerator(dest, configurations, component, message), cmInstallGenerator(dest, configurations, component, message,
exclude_from_all),
LocalGenerator(0), LocalGenerator(0),
Directories(dirs), Directories(dirs),
FilePermissions(file_permissions), DirPermissions(dir_permissions), FilePermissions(file_permissions), DirPermissions(dir_permissions),

View File

@ -27,6 +27,7 @@ public:
std::vector<std::string> const& configurations, std::vector<std::string> const& configurations,
const char* component, const char* component,
MessageLevel message, MessageLevel message,
bool exclude_from_all,
const char* literal_args, const char* literal_args,
bool optional = false); bool optional = false);
virtual ~cmInstallDirectoryGenerator(); virtual ~cmInstallDirectoryGenerator();

View File

@ -33,9 +33,11 @@ cmInstallExportGenerator::cmInstallExportGenerator(
std::vector<std::string> const& configurations, std::vector<std::string> const& configurations,
const char* component, const char* component,
MessageLevel message, MessageLevel message,
bool exclude_from_all,
const char* filename, const char* name_space, const char* filename, const char* name_space,
bool exportOld) bool exportOld)
:cmInstallGenerator(destination, configurations, component, message) :cmInstallGenerator(destination, configurations, component, message,
exclude_from_all)
,ExportSet(exportSet) ,ExportSet(exportSet)
,FilePermissions(file_permissions) ,FilePermissions(file_permissions)
,FileName(filename) ,FileName(filename)

View File

@ -31,6 +31,7 @@ public:
const std::vector<std::string>& configurations, const std::vector<std::string>& configurations,
const char* component, const char* component,
MessageLevel message, MessageLevel message,
bool exclude_from_all,
const char* filename, const char* name_space, const char* filename, const char* name_space,
bool exportOld); bool exportOld);
~cmInstallExportGenerator(); ~cmInstallExportGenerator();

View File

@ -122,6 +122,7 @@ void cmInstallFilesCommand::CreateInstallGenerator() const
// Use a file install generator. // Use a file install generator.
const char* no_permissions = ""; const char* no_permissions = "";
const char* no_rename = ""; const char* no_rename = "";
bool no_exclude_from_all = false;
std::string no_component = this->Makefile->GetSafeDefinition( std::string no_component = this->Makefile->GetSafeDefinition(
"CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"); "CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
std::vector<std::string> no_configurations; std::vector<std::string> no_configurations;
@ -131,7 +132,8 @@ void cmInstallFilesCommand::CreateInstallGenerator() const
new cmInstallFilesGenerator(this->Files, new cmInstallFilesGenerator(this->Files,
destination.c_str(), false, destination.c_str(), false,
no_permissions, no_configurations, no_permissions, no_configurations,
no_component.c_str(), message, no_rename)); no_component.c_str(), message,
no_exclude_from_all, no_rename));
} }

View File

@ -24,9 +24,11 @@ cmInstallFilesGenerator
std::vector<std::string> const& configurations, std::vector<std::string> const& configurations,
const char* component, const char* component,
MessageLevel message, MessageLevel message,
bool exclude_from_all,
const char* rename, const char* rename,
bool optional): bool optional):
cmInstallGenerator(dest, configurations, component, message), cmInstallGenerator(dest, configurations, component, message,
exclude_from_all),
LocalGenerator(0), LocalGenerator(0),
Files(files), Files(files),
FilePermissions(file_permissions), FilePermissions(file_permissions),

View File

@ -26,6 +26,7 @@ public:
std::vector<std::string> const& configurations, std::vector<std::string> const& configurations,
const char* component, const char* component,
MessageLevel message, MessageLevel message,
bool exclude_from_all,
const char* rename, const char* rename,
bool optional = false); bool optional = false);
virtual ~cmInstallFilesGenerator(); virtual ~cmInstallFilesGenerator();

View File

@ -19,11 +19,13 @@ cmInstallGenerator
::cmInstallGenerator(const char* destination, ::cmInstallGenerator(const char* destination,
std::vector<std::string> const& configurations, std::vector<std::string> const& configurations,
const char* component, const char* component,
MessageLevel message): MessageLevel message,
bool exclude_from_all):
cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations), cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations),
Destination(destination? destination:""), Destination(destination? destination:""),
Component(component? component:""), Component(component? component:""),
Message(message) Message(message),
ExcludeFromAll(exclude_from_all)
{ {
} }
@ -146,12 +148,16 @@ void cmInstallGenerator
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
std::string std::string
cmInstallGenerator::CreateComponentTest(const char* component) cmInstallGenerator::CreateComponentTest(const char* component,
bool exclude_from_all)
{ {
std::string result = "NOT CMAKE_INSTALL_COMPONENT OR " std::string result = "\"${CMAKE_INSTALL_COMPONENT}\" STREQUAL \"";
"\"${CMAKE_INSTALL_COMPONENT}\" STREQUAL \"";
result += component; result += component;
result += "\""; result += "\"";
if(!exclude_from_all)
{
result += " OR NOT CMAKE_INSTALL_COMPONENT";
}
return result; return result;
} }
@ -163,7 +169,7 @@ void cmInstallGenerator::GenerateScript(std::ostream& os)
// Begin this block of installation. // Begin this block of installation.
std::string component_test = std::string component_test =
this->CreateComponentTest(this->Component.c_str()); this->CreateComponentTest(this->Component.c_str(),this->ExcludeFromAll);
os << indent << "if(" << component_test << ")\n"; os << indent << "if(" << component_test << ")\n";
// Generate the script possibly with per-configuration code. // Generate the script possibly with per-configuration code.

View File

@ -36,7 +36,8 @@ public:
cmInstallGenerator(const char* destination, cmInstallGenerator(const char* destination,
std::vector<std::string> const& configurations, std::vector<std::string> const& configurations,
const char* component, const char* component,
MessageLevel message); MessageLevel message,
bool exclude_from_all);
virtual ~cmInstallGenerator(); virtual ~cmInstallGenerator();
void AddInstallRule( void AddInstallRule(
@ -67,12 +68,14 @@ public:
protected: protected:
virtual void GenerateScript(std::ostream& os); virtual void GenerateScript(std::ostream& os);
std::string CreateComponentTest(const char* component); std::string CreateComponentTest(const char* component,
bool exclude_from_all);
// Information shared by most generator types. // Information shared by most generator types.
std::string Destination; std::string Destination;
std::string Component; std::string Component;
MessageLevel Message; MessageLevel Message;
bool ExcludeFromAll;
}; };
#endif #endif

View File

@ -85,6 +85,7 @@ void cmInstallProgramsCommand::FinalPass()
// Use a file install generator. // Use a file install generator.
const char* no_permissions = ""; const char* no_permissions = "";
const char* no_rename = ""; const char* no_rename = "";
bool no_exclude_from_all = false;
std::string no_component = this->Makefile->GetSafeDefinition( std::string no_component = this->Makefile->GetSafeDefinition(
"CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"); "CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
std::vector<std::string> no_configurations; std::vector<std::string> no_configurations;
@ -94,7 +95,8 @@ void cmInstallProgramsCommand::FinalPass()
new cmInstallFilesGenerator(this->Files, new cmInstallFilesGenerator(this->Files,
destination.c_str(), true, destination.c_str(), true,
no_permissions, no_configurations, no_permissions, no_configurations,
no_component.c_str(), message, no_rename)); no_component.c_str(), message,
no_exclude_from_all, no_rename));
} }
/** /**

View File

@ -14,8 +14,9 @@
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmInstallScriptGenerator cmInstallScriptGenerator
::cmInstallScriptGenerator(const char* script, bool code, ::cmInstallScriptGenerator(const char* script, bool code,
const char* component) : const char* component, bool exclude_from_all) :
cmInstallGenerator(0, std::vector<std::string>(), component, MessageDefault), cmInstallGenerator(0, std::vector<std::string>(), component, MessageDefault,
exclude_from_all),
Script(script), Code(code) Script(script), Code(code)
{ {
} }
@ -31,7 +32,7 @@ void cmInstallScriptGenerator::GenerateScript(std::ostream& os)
{ {
Indent indent; Indent indent;
std::string component_test = std::string component_test =
this->CreateComponentTest(this->Component.c_str()); this->CreateComponentTest(this->Component.c_str(), this->ExcludeFromAll);
os << indent << "if(" << component_test << ")\n"; os << indent << "if(" << component_test << ")\n";
if(this->Code) if(this->Code)

View File

@ -21,7 +21,7 @@ class cmInstallScriptGenerator: public cmInstallGenerator
{ {
public: public:
cmInstallScriptGenerator(const char* script, bool code, cmInstallScriptGenerator(const char* script, bool code,
const char* component); const char* component, bool exclude_from_all);
virtual ~cmInstallScriptGenerator(); virtual ~cmInstallScriptGenerator();
protected: protected:

View File

@ -30,8 +30,10 @@ cmInstallTargetGenerator
std::vector<std::string> const& configurations, std::vector<std::string> const& configurations,
const char* component, const char* component,
MessageLevel message, MessageLevel message,
bool exclude_from_all,
bool optional): bool optional):
cmInstallGenerator(dest, configurations, component, message), cmInstallGenerator(dest, configurations, component, message,
exclude_from_all),
TargetName(targetName), TargetName(targetName),
Target(0), Target(0),
FilePermissions(file_permissions), FilePermissions(file_permissions),

View File

@ -28,6 +28,7 @@ public:
std::vector<std::string> const& configurations, std::vector<std::string> const& configurations,
const char* component, const char* component,
MessageLevel message, MessageLevel message,
bool exclude_from_all,
bool optional bool optional
); );
virtual ~cmInstallTargetGenerator(); virtual ~cmInstallTargetGenerator();

View File

@ -2557,7 +2557,7 @@ public:
cmInstallTargetGenerator( cmInstallTargetGenerator(
t, dest, implib, "", std::vector<std::string>(), "Unspecified", t, dest, implib, "", std::vector<std::string>(), "Unspecified",
cmInstallGenerator::SelectMessageLevel(lg->GetMakefile()), cmInstallGenerator::SelectMessageLevel(lg->GetMakefile()),
false) false, false)
{ {
this->Compute(lg); this->Compute(lg);
} }
@ -2584,7 +2584,7 @@ cmLocalGenerator
// Include the user-specified pre-install script for this target. // Include the user-specified pre-install script for this target.
if(const char* preinstall = (*l)->GetProperty("PRE_INSTALL_SCRIPT")) if(const char* preinstall = (*l)->GetProperty("PRE_INSTALL_SCRIPT"))
{ {
cmInstallScriptGenerator g(preinstall, false, 0); cmInstallScriptGenerator g(preinstall, false, 0, false);
g.Generate(os, config, configurationTypes); g.Generate(os, config, configurationTypes);
} }
@ -2645,7 +2645,7 @@ cmLocalGenerator
// Include the user-specified post-install script for this target. // Include the user-specified post-install script for this target.
if(const char* postinstall = (*l)->GetProperty("POST_INSTALL_SCRIPT")) if(const char* postinstall = (*l)->GetProperty("POST_INSTALL_SCRIPT"))
{ {
cmInstallScriptGenerator g(postinstall, false, 0); cmInstallScriptGenerator g(postinstall, false, 0, false);
g.Generate(os, config, configurationTypes); g.Generate(os, config, configurationTypes);
} }
} }