diff options
author | Ken Martin <ken.martin@kitware.com> | 2003-06-03 14:30:23 (GMT) |
---|---|---|
committer | Ken Martin <ken.martin@kitware.com> | 2003-06-03 14:30:23 (GMT) |
commit | ba68f771b369e65476e7ce12aa8dd1cf18d7f529 (patch) | |
tree | 4580bb0cd83663ac32e7234b47f1a03881a2b709 /Source | |
parent | 4f55e4870d0dea6f700943ccd4bac958c478cff4 (diff) | |
download | CMake-ba68f771b369e65476e7ce12aa8dd1cf18d7f529.zip CMake-ba68f771b369e65476e7ce12aa8dd1cf18d7f529.tar.gz CMake-ba68f771b369e65476e7ce12aa8dd1cf18d7f529.tar.bz2 |
yikes added new custom command support
Diffstat (limited to 'Source')
27 files changed, 1296 insertions, 822 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index bbfaf53..a707b55 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -159,6 +159,12 @@ IF(BUILD_TESTING) ADD_TEST(DumpDocumentation ${EXECUTABLE_OUTPUT_PATH}/DumpDocumentation --all-for-coverage) + ADD_TEST(CustomCommand ${EXECUTABLE_OUTPUT_PATH}/cmaketest + ${CMake_SOURCE_DIR}/Tests/CustomCommand + ${CMake_BINARY_DIR}/Tests/CustomCommand + CustomCommand + ${CMake_BINARY_DIR}/Tests/CustomCommand/bin) + ADD_TEST(SystemInformation ${EXECUTABLE_OUTPUT_PATH}/cmaketest ${CMake_SOURCE_DIR}/Tests/SystemInformation ${CMake_BINARY_DIR}/Tests/SystemInformation diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index a0a017d..d1de845 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -15,14 +15,14 @@ =========================================================================*/ #include "cmAddCustomCommandCommand.h" - +#include "cmTarget.h" // cmAddCustomCommandCommand bool cmAddCustomCommandCommand::InitialPass(std::vector<std::string> const& args) { /* Let's complain at the end of this function about the lack of a particular - arg. For the moment, let's say that COMMAND, TARGET are always - required. + arg. For the moment, let's say that COMMAND, and either TARGET or SOURCE + are required. */ if (args.size() < 4) { @@ -30,15 +30,19 @@ bool cmAddCustomCommandCommand::InitialPass(std::vector<std::string> const& args return false; } - std::string source, command, target, comment; + std::string source, command, target, comment, output, main_dependency; std::vector<std::string> command_args, depends, outputs; + cmTarget::CustomCommandType cctype = cmTarget::POST_BUILD; + enum tdoing { doing_source, doing_command, doing_target, doing_args, doing_depends, + doing_main_dependency, + doing_output, doing_outputs, doing_comment, doing_nothing @@ -58,6 +62,18 @@ bool cmAddCustomCommandCommand::InitialPass(std::vector<std::string> const& args { doing = doing_command; } + else if(copy == "PRE_BUILD") + { + cctype = cmTarget::PRE_BUILD; + } + else if(copy == "PRE_LINK") + { + cctype = cmTarget::PRE_LINK; + } + else if(copy == "POST_BUILD") + { + cctype = cmTarget::POST_BUILD; + } else if(copy == "TARGET") { doing = doing_target; @@ -74,6 +90,14 @@ bool cmAddCustomCommandCommand::InitialPass(std::vector<std::string> const& args { doing = doing_outputs; } + else if (copy == "OUTPUT") + { + doing = doing_output; + } + else if (copy == "MAIN_DEPENDENCY") + { + doing = doing_main_dependency; + } else if (copy == "COMMENT") { doing = doing_comment; @@ -85,6 +109,12 @@ bool cmAddCustomCommandCommand::InitialPass(std::vector<std::string> const& args case doing_source: source = copy; break; + case doing_output: + output = copy; + break; + case doing_main_dependency: + main_dependency = copy; + break; case doing_command: command = copy; break; @@ -114,21 +144,36 @@ bool cmAddCustomCommandCommand::InitialPass(std::vector<std::string> const& args For the moment, let's say that COMMAND, TARGET are always required. */ - - if(target.empty()) + if (output.empty() && target.empty()) { - this->SetError("Wrong syntax. Empty TARGET."); + this->SetError("Wrong syntax. A TARGET or OUTPUT must be specified."); return false; } + + // If source is empty, use the target + if(source.empty() && output.empty()) + { + m_Makefile->AddCustomCommandToTarget(target.c_str(), + command.c_str(), + command_args, + cctype, + comment.c_str()); + return true; + } - // If source is empty, use target as source, so that this command - // can be used to just attach a commmand to a target - - if(source.empty()) + // If target is empty, use the output + if(target.empty()) { - source = target; + m_Makefile->AddCustomCommandToOutput(output.c_str(), + command.c_str(), + command_args, + main_dependency.c_str(), + depends, + comment.c_str()); + return true; } + // otherwise backwards compatiblity mode m_Makefile->AddCustomCommand(source.c_str(), command.c_str(), command_args, diff --git a/Source/cmAddCustomCommandCommand.h b/Source/cmAddCustomCommandCommand.h index fe46f0e..218b676 100644 --- a/Source/cmAddCustomCommandCommand.h +++ b/Source/cmAddCustomCommandCommand.h @@ -86,42 +86,69 @@ public: virtual const char* GetFullDocumentation() { return - " ADD_CUSTOM_COMMAND(TARGET target\n" - " [SOURCE source]\n" - " [COMMAND command]\n" + "There are two main signatures for ADD_CUSTOM_COMMAND " + "The first signature is for adding a custom command " + "to a source file.\n" + " ADD_CUSTOM_COMMAND(OUTPUT result\n" + " COMMAND command\n" " [ARGS [args...]]\n" + " [MAIN_DEPENDENCY depend]\n" " [DEPENDS [depends...]]\n" - " [OUTPUTS [outputs...]]\n" " [COMMENT comment])\n" "This defines a new command that can be executed during the build " "process. In makefile terms this creates a new target in the " "following form:\n" - " OUTPUT1: SOURCE DEPENDS\n" - " COMAND ARGS\n" - " OUTPUT2: SOURCE DEPENDS\n" - " COMAND ARGS\n" - "The TARGET must be specified, but it is not the make target of the " - "build rule. It is the target (library, executable, or custom target) " - "that will use the output generated from this rule. This is necessary " - "to choose a project file in which to generate the rule for Visual " - "Studio.\n" - "Example of usage:\n" - " ADD_CUSTOM_COMMAND(\n" - " TARGET tiff\n" - " SOURCE ${TIFF_FAX_EXE}\n" - " COMMAND ${TIFF_FAX_EXE}\n" - " ARGS -c const ${TIFF_BINARY_DIR}/tif_fax3sm.c\n" - " OUTPUTS ${TIFF_BINARY_DIR}/tif_fax3sm.c\n" - " )\n" - "This will create custom target which will generate file tif_fax3sm.c " - "using command ${TIFF_FAX_EXE}. The rule will be executed as part of " - "building the tiff library because it includes tif_fax3sm.c as a " - "source file with the GENERATED property."; + " OUTPUT: MAIN_DEPENDENCY DEPENDS\n" + " COMMAND ARGS\n" + "\n" + "The second signature adds a custom command to a target " + "such as a library or executable. This is useful for " + "performing an operation before or after building the target " + "\n" + " ADD_CUSTOM_COMMAND(TARGET target\n" + " PRE_BUILD | PRE_LINK | POST_BUILD\n" + " COMMAND command\n" + " [ARGS [args...]]\n" + " [COMMENT comment])\n" + "This defines a new command that will be associated with " + "building the specified target. When the command will " + "happen is determined by whether you specify\n" + "PRE_BUILD - run before all other dependencies\n" + "PRE_LINK - run after other dependencies\n" + "POST_BUILD - run after the target has been built\n"; } cmTypeMacro(cmAddCustomCommandCommand, cmCommand); }; +/* + +target: normal depends + pre rules + normal rules + post rules + +output1: source other depends + rule + +output2: source other dpeends + rule + + +another option is + +output1: depends + rule + +output2: depends + rule + + + +use case1 - an executable that depending on args create diff output files + +*/ + #endif diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index 77ab3ef..8ab470c 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -45,14 +45,25 @@ bool cmAddCustomTargetCommand::InitialPass(std::vector<std::string> const& args) command = *s; ++s; } - for (;s != args.end(); ++s) + for (;s != args.end() && *s != "DEPENDS"; ++s) { arguments += cmSystemTools::EscapeSpaces(s->c_str()); arguments += " "; } + std::vector<std::string> depends; + // skip depends keyword + if (s != args.end()) + { + ++s; + } + while (s != args.end()) + { + depends.push_back(*s); + ++s; + } m_Makefile->AddUtilityCommand(args[0].c_str(), command.c_str(), - arguments.c_str(), all); + arguments.c_str(), all, depends); return true; } diff --git a/Source/cmAddCustomTargetCommand.h b/Source/cmAddCustomTargetCommand.h index 37f8537..778cc73 100644 --- a/Source/cmAddCustomTargetCommand.h +++ b/Source/cmAddCustomTargetCommand.h @@ -64,7 +64,8 @@ public: virtual const char* GetFullDocumentation() { return - " ADD_CUSTOM_TARGET(Name [ALL] [ command arg arg arg ... ])\n" + " ADD_CUSTOM_TARGET(Name [ALL] [ command arg arg arg ... ] " + " [DEPENDS depend depend depend ... ])\n" "Adds a target with the given name that executes the given command " "every time the target is built. If the ALL option is specified " "it indicates that this target should be added to the default build " diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx index 4bec426..90be276 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -239,6 +239,56 @@ void cmAddCustomCommand(void *arg, const char* source, mf->AddCustomCommand(source, command, args2, depends2, outputs2, target); } +void cmAddCustomCommandToOutput(void *arg, const char* output, + const char* command, + int numArgs, const char **args, + const char* main_dependency, + int numDepends, const char **depends) +{ + cmMakefile *mf = static_cast<cmMakefile *>(arg); + int i; + std::vector<std::string> args2; + for (i = 0; i < numArgs; ++i) + { + args2.push_back(args[i]); + } + std::vector<std::string> depends2; + for (i = 0; i < numDepends; ++i) + { + depends2.push_back(depends[i]); + } + mf->AddCustomCommandToOutput(output, command, args2, main_dependency, + depends2); +} + +void cmAddCustomCommandToTarget(void *arg, const char* target, + const char* command, + int numArgs, const char **args, + int commandType) +{ + cmMakefile *mf = static_cast<cmMakefile *>(arg); + int i; + std::vector<std::string> args2; + for (i = 0; i < numArgs; ++i) + { + args2.push_back(args[i]); + } + switch (commandType) + { + case CM_PRE_BUILD: + mf->AddCustomCommandToTarget(target, command, args2, + cmTarget::PRE_BUILD); + break; + case CM_PRE_LINK: + mf->AddCustomCommandToTarget(target, command, args2, + cmTarget::PRE_LINK); + break; + case CM_POST_BUILD: + mf->AddCustomCommandToTarget(target, command, args2, + cmTarget::POST_BUILD); + break; + } +} void cmAddLinkLibraryForTarget(void *arg, const char *tgt, const char*value, int libtype) @@ -546,5 +596,8 @@ cmCAPI cmStaticCAPI = cmGetFilenamePath, cmRemoveFile, cmFree, + + cmAddCustomCommandToOutput, + cmAddCustomCommandToTarget, }; diff --git a/Source/cmCPluginAPI.h b/Source/cmCPluginAPI.h index da1f6f3..311e6ab 100644 --- a/Source/cmCPluginAPI.h +++ b/Source/cmCPluginAPI.h @@ -145,6 +145,19 @@ typedef struct void (*RemoveFile)(const char *f1); void (*Free)(void *); + /*========================================================================= + The following are new functions added after 1.6 + =========================================================================*/ + void (*AddCustomCommandToOutput) (void *mf, const char* output, + const char* command, + int numArgs, const char **args, + const char* main_dependency, + int numDepends, const char **depends); + void (*AddCustomCommandToTarget) (void *mf, const char* target, + const char* command, + int numArgs, const char **args, + int commandType); + /* this is the end of the C function stub API structure */ } cmCAPI; @@ -176,6 +189,12 @@ define the different types of compiles a library may be #define CM_LIBRARY_DEBUG 1 #define CM_LIBRARY_OPTIMIZED 2 +/*========================================================================= +define the different types of custom commands for a target +=========================================================================*/ +#define CM_PRE_BUILD 0 +#define CM_PRE_LINK 1 +#define CM_POST_BUILD 2 /*========================================================================= Finally we define the key data structures and function prototypes diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index d8fafe4..378505e 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -20,47 +20,48 @@ /** * The constructor */ -cmCustomCommand::cmCustomCommand(const char *src, const char *command, +cmCustomCommand::cmCustomCommand(const char *command, const char* arguments, std::vector<std::string> dep, - std::vector<std::string> out): - m_Source(src), + const char *out): m_Command(command), m_Arguments(arguments), - m_Depends(dep), - m_Outputs(out) + m_Depends(dep) { + if (out) + { + m_Output = out; + } } +cmCustomCommand::cmCustomCommand(const char *command, + const char* arguments): + m_Command(command), + m_Arguments(arguments) +{ +} /** * Copy constructor. */ cmCustomCommand::cmCustomCommand(const cmCustomCommand& r): - m_Source(r.m_Source), m_Command(r.m_Command), m_Arguments(r.m_Arguments), m_Comment(r.m_Comment), m_Depends(r.m_Depends), - m_Outputs(r.m_Outputs) + m_Output(r.m_Output) { } void cmCustomCommand::ExpandVariables(const cmMakefile &mf) { - mf.ExpandVariablesInString(m_Source); mf.ExpandVariablesInString(m_Command); mf.ExpandVariablesInString(m_Arguments); + mf.ExpandVariablesInString(m_Output); for (std::vector<std::string>::iterator i = m_Depends.begin(); i != m_Depends.end(); ++i) { mf.ExpandVariablesInString(*i); } - for (std::vector<std::string>::iterator i = m_Outputs.begin(); - i != m_Outputs.end(); ++i) - { - mf.ExpandVariablesInString(*i); - } } - diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index 9085177..79206ac 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -28,10 +28,13 @@ class cmMakefile; class cmCustomCommand { public: - cmCustomCommand(const char *src, const char *command, + cmCustomCommand(const char *command, const char* arguments, std::vector<std::string> dep, - std::vector<std::string> out); + const char *out); + cmCustomCommand(const char *command, + const char* arguments); + cmCustomCommand() {}; cmCustomCommand(const cmCustomCommand& r); /** @@ -40,12 +43,6 @@ public: */ void ExpandVariables(const cmMakefile &); - /** - * Return the name of the source file. I'm not sure if this is a full path or not. - */ - std::string GetSourceName() const {return m_Source;} - void SetSourceName(const char *name) {m_Source = name;} - ///! Return the command to execute with arguments std::string GetCommandAndArguments() const {return m_Command + " " + m_Arguments;} @@ -54,7 +51,11 @@ public: std::string GetCommand() const {return m_Command;} void SetCommand(const char *cmd) {m_Command = cmd;} - ///! Return the command to execute + ///! Return the output + std::string GetOutput() const {return m_Output;} + void SetOutput(const char *cm) {m_Output = cm;} + + ///! Return the comment std::string GetComment() const {return m_Comment;} void SetComment(const char *cm) {m_Comment = cm;} @@ -68,19 +69,12 @@ public: const std::vector<std::string> &GetDepends() const {return m_Depends;} std::vector<std::string> &GetDepends() {return m_Depends;} - /** - * Return the vector that holds the list of outputs of this command - */ - const std::vector<std::string> &GetOutputs() const {return m_Outputs;} - std::vector<std::string> &GetOutputs() {return m_Outputs;} - private: - std::string m_Source; std::string m_Command; std::string m_Arguments; std::string m_Comment; + std::string m_Output; std::vector<std::string> m_Depends; - std::vector<std::string> m_Outputs; }; diff --git a/Source/cmGlobalVisualStudio6Generator.cxx b/Source/cmGlobalVisualStudio6Generator.cxx index 0a204cf..2189679 100644 --- a/Source/cmGlobalVisualStudio6Generator.cxx +++ b/Source/cmGlobalVisualStudio6Generator.cxx @@ -146,8 +146,9 @@ void cmGlobalVisualStudio6Generator::Generate() { // add a special target that depends on ALL projects for easy build // of Debug only + std::vector<std::string> srcs; m_LocalGenerators[0]->GetMakefile()-> - AddUtilityCommand("ALL_BUILD", "echo","\"Build all projects\"",false); + AddUtilityCommand("ALL_BUILD", "echo","\"Build all projects\"",false,srcs); // add the Run Tests command this->SetupTests(); @@ -235,8 +236,9 @@ void cmGlobalVisualStudio6Generator::SetupTests() // If the file doesn't exist, then ENABLE_TESTING hasn't been run if (cmSystemTools::FileExists(fname.c_str())) { + std::vector<std::string> srcs; m_LocalGenerators[0]->GetMakefile()-> - AddUtilityCommand("RUN_TESTS", ctest.c_str(), "-D $(IntDir)",false); + AddUtilityCommand("RUN_TESTS", ctest.c_str(), "-D $(IntDir)",false,srcs); } } } @@ -310,12 +312,13 @@ void cmGlobalVisualStudio6Generator::WriteDSWFile(std::ostream& fout) // Write the project into the DSW file if (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) { - cmCustomCommand cc = l->second.GetCustomCommands()[0]; + cmCustomCommand cc = l->second.GetPreLinkCommands()[0]; // dodgy use of the cmCustomCommand's members to store the // arguments from the INCLUDE_EXTERNAL_MSPROJECT command std::vector<std::string> stuff = cc.GetDepends(); - std::vector<std::string> depends = cc.GetOutputs(); + std::vector<std::string> depends; + depends.push_back(cc.GetOutput()); this->WriteExternalProject(fout, stuff[0].c_str(), stuff[1].c_str(), depends); ++si; } diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index d38c300..4564901 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -109,12 +109,13 @@ void cmGlobalVisualStudio71Generator::WriteSLNFile(std::ostream& fout) // Write the project into the SLN file if (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) { - cmCustomCommand cc = l->second.GetCustomCommands()[0]; + cmCustomCommand cc = l->second.GetPreLinkCommands()[0]; // dodgy use of the cmCustomCommand's members to store the // arguments from the INCLUDE_EXTERNAL_MSPROJECT command std::vector<std::string> stuff = cc.GetDepends(); - std::vector<std::string> depends = cc.GetOutputs(); + std::vector<std::string> depends; + depends.push_back(cc.GetOutput()); this->WriteExternalProject(fout, stuff[0].c_str(), stuff[1].c_str(), depends); ++si; diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 037e34a..c7d0324 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -145,8 +145,9 @@ void cmGlobalVisualStudio7Generator::SetupTests() // If the file doesn't exist, then ENABLE_TESTING hasn't been run if (cmSystemTools::FileExists(fname.c_str())) { + std::vector<std::string> srcs; m_LocalGenerators[0]->GetMakefile()-> - AddUtilityCommand("RUN_TESTS", ctest.c_str(), "-D $(IntDir)",false); + AddUtilityCommand("RUN_TESTS", ctest.c_str(), "-D $(IntDir)",false, srcs); } } } @@ -223,8 +224,9 @@ void cmGlobalVisualStudio7Generator::Generate() { // add a special target that depends on ALL projects for easy build // of Debug only + std::vector<std::string> srcs; m_LocalGenerators[0]->GetMakefile()-> - AddUtilityCommand("ALL_BUILD", "echo","\"Build all projects\"",false); + AddUtilityCommand("ALL_BUILD", "echo","\"Build all projects\"",false, srcs); // add the Run Tests command this->SetupTests(); @@ -340,12 +342,13 @@ void cmGlobalVisualStudio7Generator::WriteSLNFile(std::ostream& fout) // Write the project into the SLN file if (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) { - cmCustomCommand cc = l->second.GetCustomCommands()[0]; + cmCustomCommand cc = l->second.GetPreLinkCommands()[0]; // dodgy use of the cmCustomCommand's members to store the // arguments from the INCLUDE_EXTERNAL_MSPROJECT command std::vector<std::string> stuff = cc.GetDepends(); - std::vector<std::string> depends = cc.GetOutputs(); + std::vector<std::string> depends; + depends.push_back(cc.GetOutput()); this->WriteExternalProject(fout, stuff[0].c_str(), stuff[1].c_str(), depends); ++si; diff --git a/Source/cmLocalUnixMakefileGenerator.cxx b/Source/cmLocalUnixMakefileGenerator.cxx index 5dab6a3..7b25c72 100644 --- a/Source/cmLocalUnixMakefileGenerator.cxx +++ b/Source/cmLocalUnixMakefileGenerator.cxx @@ -422,7 +422,8 @@ void cmLocalUnixMakefileGenerator::OutputTargetRules(std::ostream& fout) for(std::vector<cmSourceFile*>::iterator i = classes.begin(); i != classes.end(); i++) { - if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY")) + if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY") && + !(*i)->GetCustomCommand()) { std::string outExt( this->GetOutputExtension((*i)->GetSourceExtension().c_str())); @@ -439,7 +440,8 @@ void cmLocalUnixMakefileGenerator::OutputTargetRules(std::ostream& fout) for(std::vector<cmSourceFile*>::iterator i = classes.begin(); i != classes.end(); i++) { - if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY")) + if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY") && + !(*i)->GetCustomCommand()) { std::string outExt(this->GetOutputExtension((*i)->GetSourceExtension().c_str())); if(outExt.size()) @@ -676,31 +678,77 @@ void cmLocalUnixMakefileGenerator::OutputLinkLibraries(std::ostream& fout, } } +std::string cmLocalUnixMakefileGenerator::CreatePreBuildRules( + const cmTarget &target, const char* targetName) +{ + std::string customRuleCode = ""; + bool initNext = false; + for (std::vector<cmCustomCommand>::const_iterator cr = + target.GetPreBuildCommands().begin(); + cr != target.GetPreBuildCommands().end(); ++cr) + { + cmCustomCommand cc(*cr); + cc.ExpandVariables(*m_Makefile); + if(initNext) + { + customRuleCode += "\n\t"; + } + else + { + initNext = true; + } + std::string command = cmSystemTools::ConvertToOutputPath(cc.GetCommand().c_str()); + customRuleCode += command + " " + cc.GetArguments(); + } + return customRuleCode; +} -std::string cmLocalUnixMakefileGenerator::CreateTargetRules(const cmTarget &target, - const char* targetName) +std::string cmLocalUnixMakefileGenerator::CreatePreLinkRules( + const cmTarget &target, const char* targetName) { std::string customRuleCode = ""; bool initNext = false; for (std::vector<cmCustomCommand>::const_iterator cr = - target.GetCustomCommands().begin(); - cr != target.GetCustomCommands().end(); ++cr) + target.GetPreLinkCommands().begin(); + cr != target.GetPreLinkCommands().end(); ++cr) { cmCustomCommand cc(*cr); cc.ExpandVariables(*m_Makefile); - if (cc.GetSourceName() == targetName) + if(initNext) { - if(initNext) - { - customRuleCode += "\n\t"; - } - else - { - initNext = true; - } - std::string command = cmSystemTools::ConvertToOutputPath(cc.GetCommand().c_str()); - customRuleCode += command + " " + cc.GetArguments(); + customRuleCode += "\n\t"; + } + else + { + initNext = true; } + std::string command = cmSystemTools::ConvertToOutputPath(cc.GetCommand().c_str()); + customRuleCode += command + " " + cc.GetArguments(); + } + return customRuleCode; +} + +std::string cmLocalUnixMakefileGenerator::CreatePostBuildRules( + const cmTarget &target, const char* targetName) +{ + std::string customRuleCode = ""; + bool initNext = false; + for (std::vector<cmCustomCommand>::const_iterator cr = + target.GetPostBuildCommands().begin(); + cr != target.GetPostBuildCommands().end(); ++cr) + { + cmCustomCommand cc(*cr); + cc.ExpandVariables(*m_Makefile); + if(initNext) + { + customRuleCode += "\n\t"; + } + else + { + initNext = true; + } + std::string command = cmSystemTools::ConvertToOutputPath(cc.GetCommand().c_str()); + customRuleCode += command + " " + cc.GetArguments(); } return customRuleCode; } @@ -848,9 +896,21 @@ void cmLocalUnixMakefileGenerator::OutputLibraryRule(std::ostream& fout, // expand multi-command semi-colon separated lists // of commands into separate commands std::vector<std::string> commands; + // collect custom commands for this target and add them to the list + std::string customCommands = this->CreatePreBuildRules(t, name); + if(customCommands.size() > 0) + { + commands.push_back(customCommands); + } + // collect custom commands for this target and add them to the list + customCommands = this->CreatePreLinkRules(t, name); + if(customCommands.size() > 0) + { + commands.push_back(customCommands); + } cmSystemTools::ExpandList(rules, commands); // collect custom commands for this target and add them to the list - std::string customCommands = this->CreateTargetRules(t, name); + customCommands = this->CreatePostBuildRules(t, name); if(customCommands.size() > 0) { commands.push_back(customCommands); @@ -1072,8 +1132,18 @@ void cmLocalUnixMakefileGenerator::OutputExecutableRule(std::ostream& fout, std::string comment = "executable"; std::vector<std::string> commands; + std::string customCommands = this->CreatePreBuildRules(t, name); + if(customCommands.size() > 0) + { + commands.push_back(customCommands.c_str()); + } + customCommands = this->CreatePreLinkRules(t, name); + if(customCommands.size() > 0) + { + commands.push_back(customCommands.c_str()); + } cmSystemTools::ExpandList(rules, commands); - std::string customCommands = this->CreateTargetRules(t, name); + customCommands = this->CreatePostBuildRules(t, name); if(customCommands.size() > 0) { commands.push_back(customCommands.c_str()); @@ -1127,8 +1197,18 @@ void cmLocalUnixMakefileGenerator::OutputUtilityRule(std::ostream& fout, const char* name, const cmTarget &t) { - std::string customCommands = this->CreateTargetRules(t, name); const char* cc = 0; + std::string customCommands = this->CreatePreBuildRules(t, name); + std::string customCommands2 = this->CreatePreLinkRules(t, name); + if(customCommands2.size() > 0) + { + customCommands += customCommands2; + } + customCommands2 = this->CreatePostBuildRules(t, name); + if(customCommands2.size() > 0) + { + customCommands += customCommands2; + } if(customCommands.size() > 0) { cc = customCommands.c_str(); @@ -1136,7 +1216,7 @@ void cmLocalUnixMakefileGenerator::OutputUtilityRule(std::ostream& fout, std::string comment = "Utility"; std::string depends; std::string replaceVars; - const std::vector<cmCustomCommand> &ccs = t.GetCustomCommands(); + const std::vector<cmCustomCommand> &ccs = t.GetPostBuildCommands(); for(std::vector<cmCustomCommand>::const_iterator i = ccs.begin(); i != ccs.end(); ++i) { @@ -1513,6 +1593,17 @@ void cmLocalUnixMakefileGenerator::OutputExeDepend(std::ostream& fout, exepath += cmSystemTools::GetExecutableExtension(); fout << cmSystemTools::ConvertToOutputPath(exepath.c_str()) << " "; } + // if it isn't in the cache, it might still be a utility target + // so check for that + else + { + std::map<cmStdString, cmTarget>& targets = m_Makefile->GetTargets(); + if (targets.find(name) != targets.end()) + { + fout << name << " "; + } + } + } @@ -1707,9 +1798,6 @@ void cmLocalUnixMakefileGenerator::OutputSubDirectoryRules(std::ostream& fout) SubDirectories); } - - - // Output the depend information for all the classes // in the makefile. These would have been generated // by the class cmMakeDepend GenerateMakefile @@ -1821,126 +1909,76 @@ void cmLocalUnixMakefileGenerator::OutputCheckDepends(std::ostream& fout) // (tab) command... void cmLocalUnixMakefileGenerator::OutputCustomRules(std::ostream& fout) { - // We may be modifying the source groups temporarily, so make a copy. - std::vector<cmSourceGroup> sourceGroups = m_Makefile->GetSourceGroups(); + // we cannot provide multiple rules for a single output + // so we will keep track of outputs to make sure we don't write + // two rules. First found wins + std::set<std::string> processedOutputs; - const cmTargets &tgts = m_Makefile->GetTargets(); - for(cmTargets::const_iterator tgt = tgts.begin(); - tgt != tgts.end(); ++tgt) - { - // add any custom rules to the source groups - for (std::vector<cmCustomCommand>::const_iterator cr = - tgt->second.GetCustomCommands().begin(); - cr != tgt->second.GetCustomCommands().end(); ++cr) - { - // if the source for the custom command is the same name - // as the target, then to not create a rule in the makefile for - // the custom command, as the command will be fired when the other target - // is built. - if ( cr->GetSourceName().compare(tgt->first) !=0) - { - cmSourceGroup& sourceGroup = - m_Makefile->FindSourceGroup(cr->GetSourceName().c_str(), - sourceGroups); - cmCustomCommand cc(*cr); - cc.ExpandVariables(*m_Makefile); - sourceGroup.AddCustomCommand(cc); - } - } - } - - // Loop through every source group. - for(std::vector<cmSourceGroup>::const_iterator sg = - sourceGroups.begin(); sg != sourceGroups.end(); ++sg) + // first output all custom rules + const std::vector<cmSourceFile*>& sources = m_Makefile->GetSourceFiles(); + for(std::vector<cmSourceFile*>::const_iterator i = sources.begin(); + i != sources.end(); ++i) { - const cmSourceGroup::BuildRules& buildRules = sg->GetBuildRules(); - if(buildRules.empty()) - { continue; } - - std::string name = sg->GetName(); - if(name != "") + if ((*i)->GetCustomCommand()) { - fout << "# Start of source group \"" << name.c_str() << "\"\n"; - } - - // Loop through each source in the source group. - for(cmSourceGroup::BuildRules::const_iterator cc = - buildRules.begin(); cc != buildRules.end(); ++ cc) - { - std::string source = cc->first; - const cmSourceGroup::Commands& commands = cc->second.m_Commands; - // Loop through every command generating code from the current source. - for(cmSourceGroup::Commands::const_iterator c = commands.begin(); - c != commands.end(); ++c) + cmCustomCommand *c = (*i)->GetCustomCommand(); + // escape spaces and convert to native slashes path for + // the command + const char* comment = c->GetComment().c_str(); + std::string command = c->GetCommand(); + cmSystemTools::ReplaceString(command, "/./", "/"); + command = cmSystemTools::ConvertToOutputPath(command.c_str()); + command += " "; + // now add the arguments + command += c->GetArguments(); + std::string depends; + // Collect out all the dependencies for this rule. + for(std::vector<std::string>::const_iterator d = + c->GetDepends().begin(); + d != c->GetDepends().end(); ++d) { - // escape spaces and convert to native slashes path for - // the command - const char* comment = c->second.m_Comment.c_str(); - std::string command = c->second.m_Command; - cmSystemTools::ReplaceString(command, "/./", "/"); - command = cmSystemTools::ConvertToOutputPath(command.c_str()); - command += " "; - // now add the arguments - command += c->second.m_Arguments; - const cmSourceGroup::CommandFiles& commandFiles = c->second; - // if the command has no outputs, then it is a utility command - // with no outputs - if(commandFiles.m_Outputs.size() == 0) - { - std::string depends; - // collect out all the dependencies for this rule. - for(std::set<std::string>::const_iterator d = - commandFiles.m_Depends.begin(); - d != commandFiles.m_Depends.end(); ++d) - { - std::string dep = *d; - cmSystemTools::ReplaceString(dep, "/./", "/"); - cmSystemTools::ReplaceString(dep, "/$(IntDir)/", "/"); - dep = cmSystemTools::ConvertToOutputPath(dep.c_str()); - depends += " "; - depends += dep; - } - // output rule - this->OutputMakeRule(fout, - (*comment?comment:"Custom command"), - source.c_str(), - depends.c_str(), - command.c_str()); - } - // Write a rule for every output generated by this command. - for(std::set<std::string>::const_iterator output = - commandFiles.m_Outputs.begin(); - output != commandFiles.m_Outputs.end(); ++output) + std::string dep = *d; + m_Makefile->ExpandVariablesInString(dep); + + // watch for target dependencies, + std::string libPath = dep + "_CMAKE_PATH"; + const char* cacheValue = m_Makefile->GetDefinition(libPath.c_str()); + if (cacheValue) { - std::string src = cmSystemTools::ConvertToOutputPath(source.c_str()); - std::string depends; - depends += src; - // Collect out all the dependencies for this rule. - for(std::set<std::string>::const_iterator d = - commandFiles.m_Depends.begin(); - d != commandFiles.m_Depends.end(); ++d) + libPath = cacheValue; + if (m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH") && + m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH")[0] != '\0') { - std::string dep = *d; - cmSystemTools::ReplaceString(dep, "/./", "/"); - cmSystemTools::ReplaceString(dep, "/$(IntDir)/", "/"); - dep = cmSystemTools::ConvertToOutputPath(dep.c_str()); - depends += " "; - depends += dep; - } - // output rule - this->OutputMakeRule(fout, - (*comment?comment:"Custom command"), - output->c_str(), - depends.c_str(), - command.c_str()); + libPath = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"); + } + libPath += "/"; + libPath += dep; + libPath += cmSystemTools::GetExecutableExtension(); + dep = libPath; } + cmSystemTools::ReplaceString(dep, "/./", "/"); + cmSystemTools::ReplaceString(dep, "/$(IntDir)/", "/"); + dep = cmSystemTools::ConvertToOutputPath(dep.c_str()); + depends += " "; + depends += dep; + } + // output rule + if (processedOutputs.find(c->GetOutput()) == processedOutputs.end()) + { + this->OutputMakeRule(fout, + (*comment?comment:"Custom command"), + c->GetOutput().c_str(), + depends.c_str(), + command.c_str()); + processedOutputs.insert(c->GetOutput()); + } + else + { + cmSystemTools::Error("An output was found with multiple rules on how to build it for output: ", + c->GetOutput().c_str()); } } - if(name != "") - { - fout << "# End of source group \"" << name.c_str() << "\"\n\n"; - } - } + } } std::string @@ -2185,7 +2223,7 @@ void cmLocalUnixMakefileGenerator::OutputMakeRules(std::ostream& fout) // collect up all the sources std::string allsources; std::map<cmStdString, cmTarget>& targets = m_Makefile->GetTargets(); - for(std::map<cmStdString, cmTarget>::const_iterator target = targets.begin(); + for(std::map<cmStdString,cmTarget>::const_iterator target = targets.begin(); target != targets.end(); ++target) { // Iterate over every source for this target. @@ -2501,11 +2539,13 @@ void cmLocalUnixMakefileGenerator::OutputSourceObjectBuildRules(std::ostream& fo exportsDef = "-D"+ export_symbol; } // Iterate over every source for this target. - const std::vector<cmSourceFile*>& sources = target->second.GetSourceFiles(); + const std::vector<cmSourceFile*>& sources = + target->second.GetSourceFiles(); for(std::vector<cmSourceFile*>::const_iterator source = sources.begin(); source != sources.end(); ++source) { - if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY")) + if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY") && + !(*source)->GetCustomCommand()) { std::string shortName; std::string sourceName; @@ -2513,11 +2553,15 @@ void cmLocalUnixMakefileGenerator::OutputSourceObjectBuildRules(std::ostream& fo // directory, we want to use the relative path for the // filename of the object file. Otherwise, we will use just // the filename portion. - if((cmSystemTools::GetFilenamePath((*source)->GetFullPath()).find(m_Makefile->GetCurrentDirectory()) == 0) - || (cmSystemTools::GetFilenamePath((*source)->GetFullPath()).find(m_Makefile-> - GetCurrentOutputDirectory()) == 0)) + if((cmSystemTools::GetFilenamePath( + (*source)->GetFullPath()).find( + m_Makefile->GetCurrentDirectory()) == 0) + || (cmSystemTools::GetFilenamePath( + (*source)->GetFullPath()).find( + m_Makefile->GetCurrentOutputDirectory()) == 0)) { - sourceName = (*source)->GetSourceName()+"."+(*source)->GetSourceExtension(); + sourceName = (*source)->GetSourceName()+"."+ + (*source)->GetSourceExtension(); shortName = (*source)->GetSourceName(); // The path may be relative. See if a directory needs to be diff --git a/Source/cmLocalUnixMakefileGenerator.h b/Source/cmLocalUnixMakefileGenerator.h index f3ebd9e..b4fc54e 100644 --- a/Source/cmLocalUnixMakefileGenerator.h +++ b/Source/cmLocalUnixMakefileGenerator.h @@ -187,8 +187,12 @@ protected: ///! return true if the two paths are the same virtual bool SamePath(const char* path1, const char* path2); virtual std::string GetOutputExtension(const char* sourceExtension); - std::string CreateTargetRules(const cmTarget &target, - const char* targetName); + std::string CreatePreBuildRules(const cmTarget &target, + const char* targetName); + std::string CreatePreLinkRules(const cmTarget &target, + const char* targetName); + std::string CreatePostBuildRules(const cmTarget &target, + const char* targetName); virtual std::string CreateMakeVariable(const char* s, const char* s2); ///! if the OS is case insensitive then return a lower case of the path. diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index 5355e3a..5b001a2 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -20,6 +20,7 @@ #include "cmSystemTools.h" #include "cmSourceFile.h" #include "cmCacheManager.h" +#include <queue> cmLocalVisualStudio6Generator::cmLocalVisualStudio6Generator() { @@ -74,6 +75,9 @@ void cmLocalVisualStudio6Generator::OutputDSPFile() // clear project names m_CreatedProjectNames.clear(); + // expand vars for custom commands + m_Makefile->ExpandVariablesInCustomCommands(); + // build any targets cmTargets &tgts = m_Makefile->GetTargets(); for(cmTargets::iterator l = tgts.begin(); @@ -154,7 +158,7 @@ void cmLocalVisualStudio6Generator::CreateSingleDSP(const char *lname, cmTarget } -void cmLocalVisualStudio6Generator::AddDSPBuildRule(cmSourceGroup& sourceGroup) +void cmLocalVisualStudio6Generator::AddDSPBuildRule() { std::string dspname = *(m_CreatedProjectNames.end()-1); if(dspname == "ALL_BUILD") @@ -169,20 +173,28 @@ void cmLocalVisualStudio6Generator::AddDSPBuildRule(cmSourceGroup& sourceGroup) std::string dsprule = "${CMAKE_COMMAND}"; m_Makefile->ExpandVariablesInString(dsprule); dsprule = cmSystemTools::ConvertToOutputPath(dsprule.c_str()); - std::string args = makefileIn; - args += " -H"; + std::vector<std::string> argv; + argv.push_back(makefileIn); + makefileIn = m_Makefile->GetStartDirectory(); + makefileIn += "/"; + makefileIn += "CMakeLists.txt"; + std::string args; + args = "-H"; args += cmSystemTools::ConvertToOutputPath(m_Makefile->GetHomeDirectory()); - args += " -S"; + argv.push_back(args); + args = "-S"; args += cmSystemTools::ConvertToOutputPath(m_Makefile->GetStartDirectory()); - args += " -O"; + argv.push_back(args); + args = "-O"; args += cmSystemTools::ConvertToOutputPath(m_Makefile->GetStartOutputDirectory()); - args += " -B"; + argv.push_back(args); + args = "-B"; args += cmSystemTools::ConvertToOutputPath(m_Makefile->GetHomeOutputDirectory()); - m_Makefile->ExpandVariablesInString(args); + argv.push_back(args); std::string configFile = m_Makefile->GetDefinition("CMAKE_ROOT"); @@ -201,14 +213,9 @@ void cmLocalVisualStudio6Generator::AddDSPBuildRule(cmSourceGroup& sourceGroup) { listFiles.push_back(configFile); } - - std::vector<std::string> outputs; - outputs.push_back(dspname); - cmCustomCommand cc(makefileIn.c_str(), dsprule.c_str(), - args.c_str(), - listFiles, - outputs); - sourceGroup.AddCustomCommand(cc); + m_Makefile->AddCustomCommandToOutput(dspname.c_str(), dsprule.c_str(), + argv, makefileIn.c_str(), listFiles, + NULL, true); } @@ -219,8 +226,87 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout, // We may be modifying the source groups temporarily, so make a copy. std::vector<cmSourceGroup> sourceGroups = m_Makefile->GetSourceGroups(); + // if we should add regen rule then... + const char *suppRegenRule = + m_Makefile->GetDefinition("CMAKE_SUPPRESS_REGENERATION"); + if (!cmSystemTools::IsOn(suppRegenRule)) + { + this->AddDSPBuildRule(); + } + // get the classes from the source lists then add them to the groups - std::vector<cmSourceFile*> classes = target.GetSourceFiles(); + std::vector<cmSourceFile*> & classes = target.GetSourceFiles(); + // use a deck to keep track of processed source files + std::queue<std::string> srcFilesToProcess; + std::string name; + for(std::vector<cmSourceFile*>::const_iterator i = classes.begin(); + i != classes.end(); ++i) + { + name = (*i)->GetSourceName(); + if ((*i)->GetSourceExtension() != "rule") + { + name += "."; + name += (*i)->GetSourceExtension(); + } + srcFilesToProcess.push(name); + } + name = libName; + name += ".dsp.cmake"; + srcFilesToProcess.push(name); + // add in the library depends for cusotm targets + if (target.GetType() == cmTarget::UTILITY) + { + cmCustomCommand &c = target.GetPostBuildCommands()[0]; + for (std::vector<std::string>::iterator i = c.GetDepends().begin(); + i != c.GetDepends().end(); ++i) + { + srcFilesToProcess.push(*i); + } + } + while (!srcFilesToProcess.empty()) + { + // is this source the output of a custom command + cmSourceFile* outsf = + m_Makefile->GetSourceFileWithOutput(srcFilesToProcess.front().c_str()); + if (outsf) + { + // is it not already in the target? + if (std::find(classes.begin(),classes.end(),outsf) == classes.end()) + { + // then add the source to this target and add it to the queue + classes.push_back(outsf); + std::string name = outsf->GetSourceName(); + if (outsf->GetSourceExtension() != "rule") + { + name += "."; + name += outsf->GetSourceExtension(); + } + srcFilesToProcess.push(name); + } + // add its dependencies to the list to check + unsigned int i; + for (i = 0; i < outsf->GetCustomCommand()->GetDepends().size(); ++i) + { + std::string dep = cmSystemTools::GetFilenameName( + outsf->GetCustomCommand()->GetDepends()[i]); + // watch for target dependencies, + std::string libPath = dep + "_CMAKE_PATH"; + const char* cacheValue = m_Makefile->GetDefinition(libPath.c_str()); + if (cacheValue) + { + // add the depend as a utility on the target + target.AddUtility(dep.c_str()); + } + else + { + srcFilesToProcess.push(dep); + } + } + } + // finished with this SF move to the next + srcFilesToProcess.pop(); + } + for(std::vector<cmSourceFile*>::iterator i = classes.begin(); i != classes.end(); i++) { @@ -231,49 +317,20 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout, sourceGroup.AddSource(source.c_str(), *i); } - // add any custom rules to the source groups - for (std::vector<cmCustomCommand>::const_iterator cr = - target.GetCustomCommands().begin(); - cr != target.GetCustomCommands().end(); ++cr) - { - cmSourceGroup& sourceGroup = - m_Makefile->FindSourceGroup(cr->GetSourceName().c_str(), - sourceGroups); - cmCustomCommand cc(*cr); - cc.ExpandVariables(*m_Makefile); - sourceGroup.AddCustomCommand(cc); - } - // Write the DSP file's header. this->WriteDSPHeader(fout, libName, target, sourceGroups); - // if we should add regen rule then... - const char *suppRegenRule = - m_Makefile->GetDefinition("CMAKE_SUPPRESS_REGENERATION"); - - // Find the group in which the CMakeLists.txt source belongs, and add - // the rule to generate this DSP file. - if (!cmSystemTools::IsOn(suppRegenRule)) - { - for(std::vector<cmSourceGroup>::reverse_iterator sg = sourceGroups.rbegin(); - sg != sourceGroups.rend(); ++sg) - { - if(sg->Matches("CMakeLists.txt")) - { - this->AddDSPBuildRule(*sg); - break; - } - } - } - // Loop through every source group. for(std::vector<cmSourceGroup>::const_iterator sg = sourceGroups.begin(); sg != sourceGroups.end(); ++sg) { - const cmSourceGroup::BuildRules& buildRules = sg->GetBuildRules(); + const std::vector<const cmSourceFile *> &sourceFiles = + sg->GetSourceFiles(); // If the group is empty, don't write it at all. - if(buildRules.empty()) - { continue; } + if(sourceFiles.empty()) + { + continue; + } // If the group has a name, write the header. std::string name = sg->GetName(); @@ -282,37 +339,32 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout, this->WriteDSPBeginGroup(fout, name.c_str(), ""); } - // Loop through each build rule in the source group. - for(cmSourceGroup::BuildRules::const_iterator cc = - buildRules.begin(); cc != buildRules.end(); ++ cc) + // Loop through each source in the source group. + for(std::vector<const cmSourceFile *>::const_iterator sf = + sourceFiles.begin(); sf != sourceFiles.end(); ++sf) { - std::string source = cc->first; - const cmSourceGroup::Commands& commands = cc->second.m_Commands; - std::vector<std::string> depends; + std::string source = (*sf)->GetFullPath(); + const cmCustomCommand *command = + (*sf)->GetCustomCommand(); std::string compileFlags; - if(cc->second.m_SourceFile) + std::vector<std::string> depends; + const char* cflags = (*sf)->GetProperty("COMPILE_FLAGS"); + if(cflags) { - // Check for extra compiler flags. - const char* cflags = cc->second.m_SourceFile->GetProperty("COMPILE_FLAGS"); - if(cflags) - { - compileFlags = cflags; - } - if(cmSystemTools::GetFileFormat( - cc->second.m_SourceFile->GetSourceExtension().c_str()) - == cmSystemTools::CXX_FILE_FORMAT) - { - // force a C++ file type - compileFlags += " /TP "; - } - - // Check for extra object-file dependencies. - const char* dependsValue = - cc->second.m_SourceFile->GetProperty("OBJECT_DEPENDS"); - if(dependsValue) - { - cmSystemTools::ExpandListArgument(dependsValue, depends); - } + compileFlags = cflags; + } + if(cmSystemTools::GetFileFormat((*sf)->GetSourceExtension().c_str()) + == cmSystemTools::CXX_FILE_FORMAT) + { + // force a C++ file type + compileFlags += " /TP "; + } + + // Check for extra object-file dependencies. + const char* dependsValue = (*sf)->GetProperty("OBJECT_DEPENDS"); + if(dependsValue) + { + cmSystemTools::ExpandListArgument(dependsValue, depends); } if (source != libName || target.GetType() == cmTarget::UTILITY) { @@ -334,18 +386,20 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout, } fout << "\n"; } - if (!commands.empty()) + if (command) { - cmSourceGroup::CommandFiles totalCommand; std::string totalCommandStr; - totalCommandStr = this->CombineCommands(commands, totalCommand, - source.c_str()); - const char* comment = totalCommand.m_Comment.c_str(); + totalCommandStr = + cmSystemTools::ConvertToOutputPath(command->GetCommand().c_str()); + totalCommandStr += " "; + totalCommandStr += command->GetArguments(); + totalCommandStr += "\n"; + const char* comment = command->GetComment().c_str(); const char* flags = compileFlags.size() ? compileFlags.c_str(): 0; this->WriteCustomRule(fout, source.c_str(), totalCommandStr.c_str(), (*comment?comment:"Custom Rule"), - totalCommand.m_Depends, - totalCommand.m_Outputs, flags); + command->GetDepends(), + command->GetOutput().c_str(), flags); } else if(compileFlags.size()) { @@ -384,8 +438,8 @@ void cmLocalVisualStudio6Generator::WriteCustomRule(std::ostream& fout, const char* source, const char* command, const char* comment, - const std::set<std::string>& depends, - const std::set<std::string>& outputs, + const std::vector<std::string>& depends, + const char *output, const char* flags ) { @@ -406,7 +460,7 @@ void cmLocalVisualStudio6Generator::WriteCustomRule(std::ostream& fout, } // Write out the dependencies for the rule. fout << "USERDEP__HACK="; - for(std::set<std::string>::const_iterator d = depends.begin(); + for(std::vector<std::string>::const_iterator d = depends.begin(); d != depends.end(); ++d) { fout << "\\\n\t" << @@ -417,21 +471,16 @@ void cmLocalVisualStudio6Generator::WriteCustomRule(std::ostream& fout, fout << "# PROP Ignore_Default_Tool 1\n"; fout << "# Begin Custom Build - Building " << comment << " $(InputPath)\n\n"; - if(outputs.size() == 0) + if(output == 0) { fout << source << "_force : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\""; fout << command << "\n\n"; } // Write a rule for every output generated by this command. - for(std::set<std::string>::const_iterator output = outputs.begin(); - output != outputs.end(); ++output) - { - fout << cmSystemTools::ConvertToOutputPath(output->c_str()) - << " : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\""; - fout << command << "\n\n"; - } - + fout << cmSystemTools::ConvertToOutputPath(output) + << " : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\""; + fout << command << "\n\n"; fout << "# End Custom Build\n\n"; } @@ -544,46 +593,6 @@ void cmLocalVisualStudio6Generator::SetBuildType(BuildType b, } } -std::string -cmLocalVisualStudio6Generator::CombineCommands(const cmSourceGroup::Commands &commands, - cmSourceGroup::CommandFiles &totalCommand, - const char *source) - -{ - // Loop through every custom command generating code from the - // current source. - // build up the depends and outputs and commands - std::string totalCommandStr = ""; - std::string temp; - for(cmSourceGroup::Commands::const_iterator c = commands.begin(); - c != commands.end(); ++c) - { - totalCommandStr += "\n\t"; - temp= c->second.m_Command; - temp = cmSystemTools::ConvertToOutputPath(temp.c_str()); - totalCommandStr += temp; - totalCommandStr += " "; - totalCommandStr += c->second.m_Arguments; - totalCommand.Merge(c->second); - totalCommand.m_Comment = c->second.m_Comment.c_str(); - } - // Create a dummy file with the name of the source if it does - // not exist - if(totalCommand.m_Outputs.empty()) - { - std::string dummyFile = m_Makefile->GetStartOutputDirectory(); - dummyFile += "/"; - dummyFile += source; - if(!cmSystemTools::FileExists(dummyFile.c_str())) - { - std::ofstream fout(dummyFile.c_str()); - fout << "Dummy file created by cmake as unused source for utility command.\n"; - } - } - return totalCommandStr; -} - - // look for custom rules on a target and collect them together std::string cmLocalVisualStudio6Generator::CreateTargetRules(const cmTarget &target, @@ -591,39 +600,85 @@ cmLocalVisualStudio6Generator::CreateTargetRules(const cmTarget &target, { std::string customRuleCode = ""; - if (target.GetType() >= cmTarget::UTILITY) + if (target.GetType() > cmTarget::UTILITY) { return customRuleCode; } + + // are there any rules? + if (target.GetPreBuildCommands().size() + + target.GetPreLinkCommands().size() + + target.GetPostBuildCommands().size() == 0) + { + return customRuleCode; + } + + customRuleCode = "# Begin Special Build Tool\n"; - // Find the group in which the lix exe custom rules belong + // Do the PreBuild and PreLink (VS6 does not support both) bool init = false; for (std::vector<cmCustomCommand>::const_iterator cr = - target.GetCustomCommands().begin(); - cr != target.GetCustomCommands().end(); ++cr) + target.GetPreBuildCommands().begin(); + cr != target.GetPreBuildCommands().end(); ++cr) { cmCustomCommand cc(*cr); cc.ExpandVariables(*m_Makefile); - if (cc.GetSourceName() == libName) + if (!init) { - if (!init) - { - // header stuff - customRuleCode = "# Begin Special Build Tool\nPostBuild_Cmds="; - init = true; - } - else - { - customRuleCode += "\t"; - } - customRuleCode += cmSystemTools::ConvertToOutputPath(cc.GetCommand().c_str()) + " " + cc.GetArguments(); + // header stuff + customRuleCode = "PreLink_Cmds="; + init = true; + } + else + { + customRuleCode += "\t"; + } + customRuleCode += cmSystemTools::ConvertToOutputPath(cc.GetCommand().c_str()) + " " + cc.GetArguments(); + } + + for (std::vector<cmCustomCommand>::const_iterator cr = + target.GetPreLinkCommands().begin(); + cr != target.GetPreLinkCommands().end(); ++cr) + { + cmCustomCommand cc(*cr); + cc.ExpandVariables(*m_Makefile); + if (!init) + { + // header stuff + customRuleCode = "PreLink_Cmds="; + init = true; + } + else + { + customRuleCode += "\t"; } + customRuleCode += cmSystemTools::ConvertToOutputPath(cc.GetCommand().c_str()) + " " + cc.GetArguments(); } - if (init) + // do the post build rules + init = false; + for (std::vector<cmCustomCommand>::const_iterator cr = + target.GetPostBuildCommands().begin(); + cr != target.GetPostBuildCommands().end(); ++cr) { - customRuleCode += "\n# End Special Build Tool\n"; + cmCustomCommand cc(*cr); + cc.ExpandVariables(*m_Makefile); + if (!init) + { + // header stuff + customRuleCode = "PostBuild_Cmds="; + init = true; + } + else + { + customRuleCode += "\t"; + } + customRuleCode += + cmSystemTools::ConvertToOutputPath(cc.GetCommand().c_str()) + + " " + cc.GetArguments(); } + + customRuleCode += "\n# End Special Build Tool\n"; return customRuleCode; } diff --git a/Source/cmLocalVisualStudio6Generator.h b/Source/cmLocalVisualStudio6Generator.h index c3b2001..f4cee58 100644 --- a/Source/cmLocalVisualStudio6Generator.h +++ b/Source/cmLocalVisualStudio6Generator.h @@ -22,9 +22,8 @@ class cmMakeDepend; class cmTarget; class cmSourceFile; - -// please remove me.... Yuck -#include "cmSourceGroup.h" +class cmSourceGroup; +class cmCustomCommand; /** \class cmLocalVisualStudio6Generator * \brief Write a LocalUnix makefiles. @@ -84,21 +83,17 @@ private: const cmTarget &tgt, std::vector<cmSourceGroup> &sgs); void WriteDSPFooter(std::ostream& fout); - void AddDSPBuildRule(cmSourceGroup&); + void AddDSPBuildRule(); void WriteCustomRule(std::ostream& fout, const char* source, const char* command, const char* comment, - const std::set<std::string>& depends, - const std::set<std::string>& outputs, + const std::vector<std::string>& depends, + const char* output, const char* flags); std::string CreateTargetRules(const cmTarget &target, const char *libName); - std::string CombineCommands(const cmSourceGroup::Commands &commands, - cmSourceGroup::CommandFiles &totalCommand, - const char *source); - std::string m_IncludeOptions; std::vector<std::string> m_Configurations; }; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index ee7225b..2aced52 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -21,6 +21,7 @@ #include "cmSourceFile.h" #include "cmCacheManager.h" #include "cmake.h" +#include <queue> cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator() { @@ -85,6 +86,9 @@ void cmLocalVisualStudio7Generator::OutputVCProjFile() // clear project names m_CreatedProjectNames.clear(); + // expand vars for custom commands + m_Makefile->ExpandVariablesInCustomCommands(); + // build any targets cmTargets &tgts = m_Makefile->GetTargets(); for(cmTargets::iterator l = tgts.begin(); @@ -127,7 +131,7 @@ void cmLocalVisualStudio7Generator::CreateSingleVCProj(const char *lname, cmTarg } -void cmLocalVisualStudio7Generator::AddVCProjBuildRule(cmSourceGroup& sourceGroup) +void cmLocalVisualStudio7Generator::AddVCProjBuildRule() { std::string dspname = *(m_CreatedProjectNames.end()-1); if(dspname == "ALL_BUILD") @@ -142,22 +146,29 @@ void cmLocalVisualStudio7Generator::AddVCProjBuildRule(cmSourceGroup& sourceGrou std::string dsprule = "${CMAKE_COMMAND}"; m_Makefile->ExpandVariablesInString(dsprule); dsprule = cmSystemTools::ConvertToOutputPath(dsprule.c_str()); - std::string args = makefileIn; - args += " -H"; + std::vector<std::string> argv; + argv.push_back(makefileIn); + makefileIn = m_Makefile->GetStartDirectory(); + makefileIn += "/"; + makefileIn += "CMakeLists.txt"; + std::string args; + args = "-H"; args += cmSystemTools::ConvertToOutputPath(m_Makefile->GetHomeDirectory()); - args += " -S"; - args += + argv.push_back(args); + args = "-S"; + args += cmSystemTools::ConvertToOutputPath(m_Makefile->GetStartDirectory()); - args += " -O"; + argv.push_back(args); + args = "-O"; args += cmSystemTools::ConvertToOutputPath(m_Makefile->GetStartOutputDirectory()); - args += " -B"; + argv.push_back(args); + args = "-B"; args += cmSystemTools::ConvertToOutputPath(m_Makefile->GetHomeOutputDirectory()); - args += ""; - m_Makefile->ExpandVariablesInString(args); - + argv.push_back(args); + std::string configFile = m_Makefile->GetDefinition("CMAKE_ROOT"); configFile += "/Templates/CMakeWindowsSystemConfig.cmake"; @@ -175,14 +186,9 @@ void cmLocalVisualStudio7Generator::AddVCProjBuildRule(cmSourceGroup& sourceGrou { listFiles.push_back(configFile); } - - std::vector<std::string> outputs; - outputs.push_back(dspname); - cmCustomCommand cc(makefileIn.c_str(), dsprule.c_str(), - args.c_str(), - listFiles, - outputs); - sourceGroup.AddCustomCommand(cc); + m_Makefile->AddCustomCommandToOutput(dspname.c_str(), dsprule.c_str(), + argv, makefileIn.c_str(), listFiles, + NULL, true); } @@ -359,10 +365,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, } fout << "\"\n/>\n"; fout << "\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"/>\n"; - fout << "\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\""; this->OutputTargetRules(fout, target, libName); - fout << "/>\n"; - fout << "\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"/>\n"; this->OutputBuildTool(fout, configName, libName, target); fout << "\t\t</Configuration>\n"; } @@ -635,18 +638,104 @@ void cmLocalVisualStudio7Generator::OutputDefineFlags(std::ostream& fout) } void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, - const char *libName, - cmTarget &target) + const char *libName, + cmTarget &target) { // get the configurations std::vector<std::string> *configs = - static_cast<cmGlobalVisualStudio7Generator *>(m_GlobalGenerator)->GetConfigurations(); + static_cast<cmGlobalVisualStudio7Generator *> + (m_GlobalGenerator)->GetConfigurations(); + // if we should add regen rule then... + const char *suppRegenRule = + m_Makefile->GetDefinition("CMAKE_SUPPRESS_REGENERATION"); + if (!cmSystemTools::IsOn(suppRegenRule)) + { + this->AddVCProjBuildRule(); + } + // We may be modifying the source groups temporarily, so make a copy. std::vector<cmSourceGroup> sourceGroups = m_Makefile->GetSourceGroups(); // get the classes from the source lists then add them to the groups - std::vector<cmSourceFile*> const& classes = target.GetSourceFiles(); + std::vector<cmSourceFile*> & classes = target.GetSourceFiles(); + // use a deck to keep track of processed source files + std::queue<std::string> srcFilesToProcess; + std::string name; + for(std::vector<cmSourceFile*>::const_iterator i = classes.begin(); + i != classes.end(); ++i) + { + std::string name = (*i)->GetSourceName(); + if ((*i)->GetSourceExtension() != "rule") + { + name += "."; + name += (*i)->GetSourceExtension(); + } + srcFilesToProcess.push(name); + } + // add in the project file itself + name = libName; + name += ".vcproj.cmake"; + srcFilesToProcess.push(name); + // add in the library depends for cusotm targets + if (target.GetType() == cmTarget::UTILITY) + { + cmCustomCommand &c = target.GetPostBuildCommands()[0]; + for (std::vector<std::string>::iterator i = c.GetDepends().begin(); + i != c.GetDepends().end(); ++i) + { + srcFilesToProcess.push(*i); + } + } + while (!srcFilesToProcess.empty()) + { + // is this source the output of a custom command + cmSourceFile* outsf = + m_Makefile->GetSourceFileWithOutput(srcFilesToProcess.front().c_str()); + if (outsf) + { + // is it not already in the target? + if (std::find(classes.begin(),classes.end(),outsf) == classes.end()) + { + // then add the source to this target and add it to the queue + classes.push_back(outsf); + std::string name = outsf->GetSourceName(); + if (outsf->GetSourceExtension() != "rule") + { + name += "."; + name += outsf->GetSourceExtension(); + } + srcFilesToProcess.push(name); + } + // add its dependencies to the list to check + unsigned int i; + for (i = 0; i < outsf->GetCustomCommand()->GetDepends().size(); ++i) + { + std::string dep = cmSystemTools::GetFilenameName( + outsf->GetCustomCommand()->GetDepends()[i]); + if (cmSystemTools::GetFilenameLastExtension(dep) == ".exe") + { + dep = cmSystemTools::GetFilenameWithoutLastExtension(dep); + } + // watch for target dependencies, + std::string libPath = dep + "_CMAKE_PATH"; + const char* cacheValue = m_Makefile->GetDefinition(libPath.c_str()); + if (cacheValue) + { + // add the depend as a utility on the target + target.AddUtility(dep.c_str()); + } + else + { + srcFilesToProcess.push(dep); + } + } + } + // finished with this SF move to the next + srcFilesToProcess.pop(); + } + + // get the classes from the source lists then add them to the groups for(std::vector<cmSourceFile*>::const_iterator i = classes.begin(); i != classes.end(); i++) { @@ -656,23 +745,9 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, { m_ModuleDefinitionFile = (*i)->GetFullPath(); } - - cmSourceGroup& sourceGroup = m_Makefile->FindSourceGroup(source.c_str(), - sourceGroups); - sourceGroup.AddSource(source.c_str(), *i); - } - - // add any custom rules to the source groups - for (std::vector<cmCustomCommand>::const_iterator cr = - target.GetCustomCommands().begin(); - cr != target.GetCustomCommands().end(); ++cr) - { cmSourceGroup& sourceGroup = - m_Makefile->FindSourceGroup(cr->GetSourceName().c_str(), - sourceGroups); - cmCustomCommand cc(*cr); - cc.ExpandVariables(*m_Makefile); - sourceGroup.AddCustomCommand(cc); + m_Makefile->FindSourceGroup(source.c_str(), sourceGroups); + sourceGroup.AddSource(source.c_str(), *i); } // open the project @@ -682,34 +757,18 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, fout << "\t<Files>\n"; - // if we should add regen rule then... - const char *suppRegenRule = - m_Makefile->GetDefinition("CMAKE_SUPPRESS_REGENERATION"); - - // Find the group in which the CMakeLists.txt source belongs, and add - // the rule to generate this VCProj file. - if (!cmSystemTools::IsOn(suppRegenRule)) - { - for(std::vector<cmSourceGroup>::reverse_iterator sg = - sourceGroups.rbegin(); - sg != sourceGroups.rend(); ++sg) - { - if(sg->Matches("CMakeLists.txt")) - { - this->AddVCProjBuildRule(*sg); - break; - } - } - } // Loop through every source group. for(std::vector<cmSourceGroup>::const_iterator sg = sourceGroups.begin(); sg != sourceGroups.end(); ++sg) { - const cmSourceGroup::BuildRules& buildRules = sg->GetBuildRules(); + const std::vector<const cmSourceFile *> &sourceFiles = + sg->GetSourceFiles(); // If the group is empty, don't write it at all. - if(buildRules.empty()) - { continue; } + if(sourceFiles.empty()) + { + continue; + } // If the group has a name, write the header. std::string name = sg->GetName(); @@ -718,45 +777,41 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, this->WriteVCProjBeginGroup(fout, name.c_str(), ""); } - // Loop through each build rule in the source group. - for(cmSourceGroup::BuildRules::const_iterator cc = - buildRules.begin(); cc != buildRules.end(); ++ cc) + // Loop through each source in the source group. + for(std::vector<const cmSourceFile *>::const_iterator sf = + sourceFiles.begin(); sf != sourceFiles.end(); ++sf) { - std::string source = cc->first; - const cmSourceGroup::Commands& commands = cc->second.m_Commands; + std::string source = (*sf)->GetFullPath(); + const cmCustomCommand *command = (*sf)->GetCustomCommand(); std::string compileFlags; std::string additionalDeps; - if(cc->second.m_SourceFile) + + // Check for extra compiler flags. + const char* cflags = (*sf)->GetProperty("COMPILE_FLAGS"); + if(cflags) { - // Check for extra compiler flags. - const char* cflags = cc->second.m_SourceFile->GetProperty("COMPILE_FLAGS"); - if(cflags) - { - compileFlags = cc->second.m_SourceFile->GetProperty("COMPILE_FLAGS"); - } - if(cmSystemTools::GetFileFormat( - cc->second.m_SourceFile->GetSourceExtension().c_str()) - == cmSystemTools::CXX_FILE_FORMAT) - { - // force a C++ file type - compileFlags += " /TP "; - } - // Check for extra object-file dependencies. - const char* deps = - cc->second.m_SourceFile->GetProperty("OBJECT_DEPENDS"); - if(deps) + compileFlags = cflags; + } + if(cmSystemTools::GetFileFormat((*sf)->GetSourceExtension().c_str()) + == cmSystemTools::CXX_FILE_FORMAT) + { + // force a C++ file type + compileFlags += " /TP "; + } + // Check for extra object-file dependencies. + const char* deps = (*sf)->GetProperty("OBJECT_DEPENDS"); + if(deps) + { + std::vector<std::string> depends; + cmSystemTools::ExpandListArgument(deps, depends); + if(!depends.empty()) { - std::vector<std::string> depends; - cmSystemTools::ExpandListArgument(deps, depends); - if(!depends.empty()) + std::vector<std::string>::iterator i = depends.begin(); + additionalDeps = this->ConvertToXMLOutputPath(i->c_str()); + for(++i;i != depends.end(); ++i) { - std::vector<std::string>::iterator i = depends.begin(); - additionalDeps = this->ConvertToXMLOutputPath(i->c_str()); - for(++i;i != depends.end(); ++i) - { - additionalDeps += ";"; - additionalDeps += this->ConvertToXMLOutputPath(i->c_str()); - } + additionalDeps += ";"; + additionalDeps += this->ConvertToXMLOutputPath(i->c_str()); } } } @@ -767,18 +822,20 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, // Tell MS-Dev what the source is. If the compiler knows how to // build it, then it will. fout << "\t\t\t\tRelativePath=\"" << d << "\">\n"; - if (!commands.empty()) + if (command) { - cmSourceGroup::CommandFiles totalCommand; std::string totalCommandStr; - totalCommandStr = this->CombineCommands(commands, totalCommand, - source.c_str()); - const char* comment = totalCommand.m_Comment.c_str(); + totalCommandStr = + cmSystemTools::ConvertToOutputPath(command->GetCommand().c_str()); + totalCommandStr += " "; + totalCommandStr += command->GetArguments(); + totalCommandStr += "\n"; + const char* comment = command->GetComment().c_str(); const char* flags = compileFlags.size() ? compileFlags.c_str(): 0; this->WriteCustomRule(fout, source.c_str(), totalCommandStr.c_str(), (*comment?comment:"Custom Rule"), - totalCommand.m_Depends, - totalCommand.m_Outputs, flags); + command->GetDepends(), + command->GetOutput().c_str(), flags); } else if(compileFlags.size() || additionalDeps.length()) { @@ -820,13 +877,14 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, } -void cmLocalVisualStudio7Generator::WriteCustomRule(std::ostream& fout, - const char* source, - const char* command, - const char* comment, - const std::set<std::string>& depends, - const std::set<std::string>& outputs, - const char* compileFlags) +void cmLocalVisualStudio7Generator:: +WriteCustomRule(std::ostream& fout, + const char* source, + const char* command, + const char* comment, + const std::vector<std::string>& depends, + const char *output, + const char* compileFlags) { std::string cmd = command; cmSystemTools::ReplaceString(cmd, "\"", """); @@ -847,17 +905,13 @@ void cmLocalVisualStudio7Generator::WriteCustomRule(std::ostream& fout, fout << "\t\t\t\t\t<Tool\n" << "\t\t\t\t\tName=\"VCCustomBuildTool\"\n" << "\t\t\t\t\tDescription=\"Building " << comment; - std::set<std::string>::const_iterator it; - for ( it = outputs.begin(); it != outputs.end(); it ++ ) - { - fout << " " << *it; - } + fout << " " << output; fout << "\"\n" << "\t\t\t\t\tCommandLine=\"" << cmd << "\n\"\n" << "\t\t\t\t\tAdditionalDependencies=\""; // Write out the dependencies for the rule. std::string temp; - for(std::set<std::string>::const_iterator d = depends.begin(); + for(std::vector<std::string>::const_iterator d = depends.begin(); d != depends.end(); ++d) { fout << this->ConvertToXMLOutputPath(d->c_str()) @@ -865,26 +919,14 @@ void cmLocalVisualStudio7Generator::WriteCustomRule(std::ostream& fout, } fout << "\"\n"; fout << "\t\t\t\t\tOutputs=\""; - if(outputs.size() == 0) + if(output == 0) { fout << source << "_force"; } bool first = true; - // Write a rule for every output generated by this command. - for(std::set<std::string>::const_iterator output = outputs.begin(); - output != outputs.end(); ++output) - { - if(!first) - { - fout << ";"; - } - else - { - first = false; - } - fout << this->ConvertToXMLOutputPathSingle(output->c_str()); - } + // Write a rule for the output generated by this command. + fout << this->ConvertToXMLOutputPathSingle(output); fout << "\"/>\n"; fout << "\t\t\t\t</FileConfiguration>\n"; } @@ -907,85 +949,90 @@ void cmLocalVisualStudio7Generator::WriteVCProjEndGroup(std::ostream& fout) } - - - -std::string -cmLocalVisualStudio7Generator::CombineCommands( - const cmSourceGroup::Commands &commands, - cmSourceGroup::CommandFiles &totalCommand, - const char *source) - +// look for custom rules on a target and collect them together +void cmLocalVisualStudio7Generator::OutputTargetRules(std::ostream& fout, + const cmTarget &target, + const char *libName) { - // Loop through every custom command generating code from the - // current source. - // build up the depends and outputs and commands - std::string totalCommandStr = ""; - std::string temp; - for(cmSourceGroup::Commands::const_iterator c = commands.begin(); - c != commands.end(); ++c) + if (target.GetType() > cmTarget::UTILITY) { - temp= - cmSystemTools::ConvertToOutputPath(c->second.m_Command.c_str()); - totalCommandStr += temp; - totalCommandStr += " "; - totalCommandStr += c->second.m_Arguments; - totalCommandStr += "\n"; - totalCommand.Merge(c->second); - totalCommand.m_Comment = c->second.m_Comment.c_str(); - } - // Create a dummy file with the name of the source if it does - // not exist - if(totalCommand.m_Outputs.empty()) - { - std::string dummyFile = m_Makefile->GetStartOutputDirectory(); - dummyFile += "/"; - dummyFile += source; - if(!cmSystemTools::FileExists(dummyFile.c_str())) + return; + } + + // add the pre build rules + fout << "\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\""; + bool init = false; + for (std::vector<cmCustomCommand>::const_iterator cr = + target.GetPreBuildCommands().begin(); + cr != target.GetPreBuildCommands().end(); ++cr) + { + cmCustomCommand cc(*cr); + cc.ExpandVariables(*m_Makefile); + if(!init) { - std::ofstream fout(dummyFile.c_str()); - fout << "Dummy file created by cmake as unused source for utility command.\n"; + fout << "\nCommandLine=\""; + init = true; } + std::string args = cc.GetArguments(); + cmSystemTools::ReplaceString(args, "\"", """); + fout << this->ConvertToXMLOutputPath(cc.GetCommand().c_str()) << " " << + args << "\n"; } - return totalCommandStr; -} - - -// look for custom rules on a target and collect them together + if (init) + { + fout << "\""; + } + fout << "/>\n"; -void cmLocalVisualStudio7Generator::OutputTargetRules(std::ostream& fout, - const cmTarget &target, - const char *libName) -{ - if (target.GetType() >= cmTarget::UTILITY) + // add the pre Link rules + fout << "\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\""; + init = false; + for (std::vector<cmCustomCommand>::const_iterator cr = + target.GetPreLinkCommands().begin(); + cr != target.GetPreLinkCommands().end(); ++cr) { - return; + cmCustomCommand cc(*cr); + cc.ExpandVariables(*m_Makefile); + if(!init) + { + fout << "\nCommandLine=\""; + init = true; + } + std::string args = cc.GetArguments(); + cmSystemTools::ReplaceString(args, "\"", """); + fout << this->ConvertToXMLOutputPath(cc.GetCommand().c_str()) << " " << + args << "\n"; + } + if (init) + { + fout << "\""; } + fout << "/>\n"; - // Find the group in which the lix exe custom rules belong - bool init = false; + // add the PostBuild rules + fout << "\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\""; + init = false; for (std::vector<cmCustomCommand>::const_iterator cr = - target.GetCustomCommands().begin(); - cr != target.GetCustomCommands().end(); ++cr) + target.GetPostBuildCommands().begin(); + cr != target.GetPostBuildCommands().end(); ++cr) { cmCustomCommand cc(*cr); cc.ExpandVariables(*m_Makefile); - if (cc.GetSourceName() == libName) + if(!init) { - if(!init) - { - fout << "\nCommandLine=\""; - init = true; - } - std::string args = cc.GetArguments(); - cmSystemTools::ReplaceString(args, "\"", """); - fout << this->ConvertToXMLOutputPath(cc.GetCommand().c_str()) << " " << args << "\n"; + fout << "\nCommandLine=\""; + init = true; } + std::string args = cc.GetArguments(); + cmSystemTools::ReplaceString(args, "\"", """); + fout << this->ConvertToXMLOutputPath(cc.GetCommand().c_str()) << " " << + args << "\n"; } if (init) { fout << "\""; } + fout << "/>\n"; } void diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 9469c5f..df711b7 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -22,9 +22,8 @@ class cmMakeDepend; class cmTarget; class cmSourceFile; - -// please remove me.... Yuck -#include "cmSourceGroup.h" +class cmCustomCommand; +class cmSourceGroup; /** \class cmLocalVisualStudio7Generator * \brief Write a LocalUnix makefiles. @@ -74,7 +73,7 @@ private: void CreateSingleVCProj(const char *lname, cmTarget &tgt); void WriteVCProjFile(std::ostream& fout, const char *libName, cmTarget &tgt); - void AddVCProjBuildRule(cmSourceGroup&); + void AddVCProjBuildRule(); void WriteConfigurations(std::ostream& fout, const char *libName, const cmTarget &tgt); @@ -107,15 +106,12 @@ private: const char* group, const char* filter); void WriteVCProjEndGroup(std::ostream& fout); - std::string CombineCommands(const cmSourceGroup::Commands &commands, - cmSourceGroup::CommandFiles &totalCommand, - const char *source); void WriteCustomRule(std::ostream& fout, const char* source, const char* command, const char* comment, - const std::set<std::string>& depends, - const std::set<std::string>& outputs, + const std::vector<std::string>& depends, + const char* output, const char* extraFlags); std::vector<std::string> m_CreatedProjectNames; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index a71de1b..661841b 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -65,6 +65,7 @@ cmMakefile::cmMakefile() this->AddSourceGroup("Source Files", "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|m|mm|rc|def|r|odl|idl|hpj|bat)$"); this->AddSourceGroup("Header Files", "\\.(h|h\\+\\+|hm|hpp|hxx|in|txx|inl)$"); + this->AddSourceGroup("CMake Rules", "\\.rule$"); this->AddDefaultDefinitions(); } @@ -169,7 +170,7 @@ void cmMakefile::Print() const for( std::vector<cmSourceGroup>::const_iterator i = m_SourceGroups.begin(); i != m_SourceGroups.end(); ++i) { - i->Print(); + std::cout << "Source Group: " << i->GetName() << std::endl; } } @@ -441,6 +442,7 @@ void cmMakefile::ConfigureFinalPass() } +// this is the old style signature, we convert to new style void cmMakefile::AddCustomCommand(const char* source, const char* command, const std::vector<std::string>& commandArgs, @@ -449,13 +451,137 @@ void cmMakefile::AddCustomCommand(const char* source, const char *target, const char *comment) { + if (strcmp(source,target)) + { + // what a pain, for backwards compatibility we will try to + // convert this to an output based rule... so for each output.. + for(std::vector<std::string>::const_iterator d = outputs.begin(); + d != outputs.end(); ++d) + { + this->AddCustomCommandToOutput(d->c_str(), command, commandArgs, + source, depends, comment); + // add the output to the target? + std::string sname = *d; + sname += ".rule"; + if (!this->GetSource(sname.c_str())) + { + m_Targets[target].GetSourceLists().push_back(source); + } + } + } + else + { + this->AddCustomCommandToTarget(target, command, commandArgs, + cmTarget::POST_BUILD, + comment); + } +} + +void cmMakefile::AddCustomCommand(const char* source, + const char* command, + const std::vector<std::string>& commandArgs, + const std::vector<std::string>& depends, + const char* output, + const char *target) +{ + std::vector<std::string> outputs; + outputs.push_back(output); + this->AddCustomCommand(source, command, commandArgs, depends, + outputs, target); +} + +void cmMakefile:: +AddCustomCommandToOutput(const char* output, + const char* command, + const std::vector<std::string>& commandArgs, + const char *main_dependency, + const std::vector<std::string>& depends, + const char *comment, + bool replace) +{ + cmSourceFile *file = 0; + std::string outName = output; + outName += ".rule"; + + // OK this rule will be placed on a generated output file unless the main + // depednency was specified. + if (main_dependency && main_dependency[0] != '\0') + { + file = this->GetSource(main_dependency); + if (file && file->GetCustomCommand() && !replace) + { + // generate a source instead + file = 0; + } + else + { + file = this->GetOrCreateSource(main_dependency); + } + } + + if (!file) + { + file = this->GetSource(outName.c_str()); + if (file && file->GetCustomCommand() && !replace) + { + cmSystemTools::Error("Attempt to add a custom rule to an output that already has a custom rule. For output: ", output); + return; + } + // create a cmSourceFile for the output + file = this->GetOrCreateSource(outName.c_str(), true); + // always mark as generated + file->SetProperty("GENERATED","1"); + } + + // always create the output and mark it generated + cmSourceFile *out = this->GetOrCreateSource(output, true); + out->SetProperty("GENERATED","1"); + + // process the command + std::string expandC = command; + this->ExpandVariablesInString(expandC); + std::string c = cmSystemTools::EscapeSpaces(expandC.c_str()); + + std::string combinedArgs; + unsigned int i; + for (i = 0; i < commandArgs.size(); ++i) + { + expandC = commandArgs[i].c_str(); + this->ExpandVariablesInString(expandC); + combinedArgs += cmSystemTools::EscapeSpaces(expandC.c_str()); + combinedArgs += " "; + } + std::vector<std::string> depends2(depends); + if (main_dependency && main_dependency[0] != '\0') + { + depends2.push_back(main_dependency); + } + cmCustomCommand *cc = + new cmCustomCommand(c.c_str(),combinedArgs.c_str(),depends2, output); + if ( comment && comment[0] ) + { + cc->SetComment(comment); + } + if (file->GetCustomCommand()) + { + delete file->GetCustomCommand(); + } + file->SetCustomCommand(cc); +} + +void cmMakefile:: +AddCustomCommandToTarget(const char* target, const char* command, + const std::vector<std::string>& commandArgs, + cmTarget::CustomCommandType type, + const char *comment) +{ // find the target, if (m_Targets.find(target) != m_Targets.end()) { std::string expandC = command; this->ExpandVariablesInString(expandC); std::string c = cmSystemTools::EscapeSpaces(expandC.c_str()); - + std::string combinedArgs; unsigned int i; @@ -467,12 +593,23 @@ void cmMakefile::AddCustomCommand(const char* source, combinedArgs += " "; } - cmCustomCommand cc(source,c.c_str(),combinedArgs.c_str(),depends,outputs); + cmCustomCommand cc(c.c_str(),combinedArgs.c_str()); if ( comment && comment[0] ) { cc.SetComment(comment); } - m_Targets[target].GetCustomCommands().push_back(cc); + switch (type) + { + case cmTarget::PRE_BUILD: + m_Targets[target].GetPreBuildCommands().push_back(cc); + break; + case cmTarget::PRE_LINK: + m_Targets[target].GetPreLinkCommands().push_back(cc); + break; + case cmTarget::POST_BUILD: + m_Targets[target].GetPostBuildCommands().push_back(cc); + break; + } std::string cacheCommand = command; this->ExpandVariablesInString(cacheCommand); if(this->GetCacheManager()->GetCacheValue(cacheCommand.c_str())) @@ -483,18 +620,6 @@ void cmMakefile::AddCustomCommand(const char* source, } } -void cmMakefile::AddCustomCommand(const char* source, - const char* command, - const std::vector<std::string>& commandArgs, - const std::vector<std::string>& depends, - const char* output, - const char *target) -{ - std::vector<std::string> outputs; - outputs.push_back(output); - this->AddCustomCommand(source, command, commandArgs, depends, outputs, target); -} - void cmMakefile::AddDefineFlag(const char* flag) { m_DefineFlags += " "; @@ -799,11 +924,12 @@ void cmMakefile::AddExecutable(const char *exeName, void cmMakefile::AddUtilityCommand(const char* utilityName, const char* command, const char* arguments, - bool all) + bool all, + const std::vector<std::string> &depends) { std::vector<std::string> empty; this->AddUtilityCommand(utilityName,command,arguments,all, - empty,empty); + depends, empty); } void cmMakefile::AddUtilityCommand(const char* utilityName, @@ -816,11 +942,54 @@ void cmMakefile::AddUtilityCommand(const char* utilityName, cmTarget target; target.SetType(cmTarget::UTILITY); target.SetInAll(all); - cmCustomCommand cc(utilityName, command, arguments, dep, out); - target.GetCustomCommands().push_back(cc); + if (out.size() > 1) + { + cmSystemTools::Error( + "Utility targets can only have one output. For utilityNamed: ", + utilityName); + return; + } + if (out.size()) + { + cmCustomCommand cc(command, arguments, dep, out[0].c_str()); + target.GetPostBuildCommands().push_back(cc); + } + else + { + cmCustomCommand cc(command, arguments, dep, NULL); + target.GetPostBuildCommands().push_back(cc); + } m_Targets.insert(cmTargets::value_type(utilityName,target)); } +cmSourceFile *cmMakefile::GetSourceFileWithOutput(const char *cname) +{ + std::string name = cname; + + // look through all the source files that have custom commands + // and see if the custom command has the passed source file as an output + // keep in mind the possible .rule extension that may be tacked on + for(std::vector<cmSourceFile*>::const_iterator i = m_SourceFiles.begin(); + i != m_SourceFiles.end(); ++i) + { + // does this source file have a custom command? + if ((*i)->GetCustomCommand()) + { + // is the output of the custom command match the source files name + std::string out = (*i)->GetCustomCommand()->GetOutput(); + if (out.rfind(name) != out.npos && + out.rfind(name) == out.size() - name.size()) + { + return *i; + } + } + } + + // otherwise return NULL + return NULL; +} + + cmSourceGroup* cmMakefile::GetSourceGroup(const char* name) { // First see if the group exists. If so, replace its regular expression. @@ -946,6 +1115,19 @@ void cmMakefile::ExpandVariables() } } +void cmMakefile::ExpandVariablesInCustomCommands() +{ + for(std::vector<cmSourceFile*>::iterator i = m_SourceFiles.begin(); + i != m_SourceFiles.end(); ++i) + { + cmCustomCommand *cc = (*i)->GetCustomCommand(); + if (cc) + { + cc->ExpandVariables(*this); + } + } +} + bool cmMakefile::IsOn(const char* name) const { const char* value = this->GetDefinition(name); @@ -1254,7 +1436,7 @@ cmMakefile::FindSourceGroup(const char* source, std::string::size_type pos = file.rfind('/'); if(pos != std::string::npos) { - file = file.substr(pos, file.length()-pos); + file = file.substr(pos+1); } for(std::vector<cmSourceGroup>::reverse_iterator sg = groups.rbegin(); @@ -1402,11 +1584,11 @@ cmSourceFile* cmMakefile::GetSource(const char* sourceName) const { std::string s = cmSystemTools::GetFilenameName(sourceName); std::string ext; - std::string::size_type pos = s.rfind('.'); - if(pos != std::string::npos) + ext = cmSystemTools::GetFilenameLastExtension(s); + s = s.substr(0, s.length()-ext.length()); + if ( ext.length() && ext[0] == '.' ) { - ext = s.substr(pos+1, s.size() - pos-1); - s = s.substr(0, pos); + ext = ext.substr(1); } for(std::vector<cmSourceFile*>::const_iterator i = m_SourceFiles.begin(); i != m_SourceFiles.end(); ++i) @@ -1422,8 +1604,71 @@ cmSourceFile* cmMakefile::GetSource(const char* sourceName) const return 0; } +cmSourceFile* cmMakefile::GetOrCreateSource(const char* sourceName, + bool generated) +{ + // check to see if it exists + cmSourceFile* ret = this->GetSource(sourceName); + if (ret) + { + return ret; + } + + // we must create one + std::string newfile = sourceName; + cmSourceFile file; + std::string path = cmSystemTools::GetFilenamePath(newfile); + if(generated) + { + std::string ext = cmSystemTools::GetFilenameLastExtension(newfile); + std::string name_no_ext = cmSystemTools::GetFilenameName(newfile.c_str()); + name_no_ext = name_no_ext.substr(0, name_no_ext.length()-ext.length()); + if ( ext.length() && ext[0] == '.' ) + { + ext = ext.substr(1); + } + if((path.size() && path[0] == '/') || + (path.size() > 1 && path[1] == ':')) + { + file.SetName(name_no_ext.c_str(), path.c_str(), ext.c_str(), false); + } + else + { + file.SetName(name_no_ext.c_str(), this->GetCurrentOutputDirectory(), + ext.c_str(), false); + } + } + else + { + // if this is a full path then + if((path.size() && path[0] == '/') || + (path.size() > 1 && path[1] == ':')) + { + file.SetName(cmSystemTools::GetFilenameName(newfile.c_str()).c_str(), + path.c_str(), + this->GetSourceExtensions(), + this->GetHeaderExtensions()); + } + else + { + file.SetName(newfile.c_str(), this->GetCurrentDirectory(), + this->GetSourceExtensions(), + this->GetHeaderExtensions()); + } + } + // add the source file to the makefile + this->AddSource(file); + ret = this->GetSource(sourceName); + if (!ret) + { + cmSystemTools::Error( + "CMake failed to properly look up cmSourceFile: ", sourceName); + int i = *(int *)0x0; + } + return ret; +} - + cmSourceFile* cmMakefile::AddSource(cmSourceFile const&sf) { // check to see if it exists diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 3180847..93d02c8 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -121,6 +121,22 @@ public: /** * Add a custom command to the build. */ + void AddCustomCommandToOutput(const char* output, + const char* command, + const std::vector<std::string>& commandArgs, + const char *main_dependency, + const std::vector<std::string>& depends, + const char *comment = 0, + bool replace = false); + void AddCustomCommandToTarget(const char* target, + const char* command, + const std::vector<std::string>& commandArgs, + cmTarget::CustomCommandType type, + const char *comment = 0); + + /** + * Add a custom command to the build. + */ void AddCustomCommand(const char* source, const char* command, const std::vector<std::string>& commandArgs, @@ -156,7 +172,8 @@ public: void AddUtilityCommand(const char* utilityName, const char* command, const char* arguments, - bool all); + bool all, + const std::vector<std::string> &depends); void AddUtilityCommand(const char* utilityName, const char* command, const char* arguments, @@ -417,6 +434,14 @@ public: cmSourceFile* GetSource(const char* sourceName) const; ///! Add a new cmSourceFile to the list of sources for this makefile. cmSourceFile* AddSource(cmSourceFile const&); + + /** Get a cmSourceFile pointer for a given source name, if the name is + * not found, then create the source file and return it. generated + * indicates if it is a generated file, this is used in determining + * how to create the source file instance e.g. name + */ + cmSourceFile* GetOrCreateSource(const char* sourceName, + bool generated = false); /** * Obtain a list of auxiliary source directories. @@ -508,7 +533,8 @@ public: * Expand variables in the makefiles ivars such as link directories etc */ void ExpandVariables(); - + void ExpandVariablesInCustomCommands(); + /** * find what source group this source is in */ @@ -559,6 +585,19 @@ public: */ cmake *GetCMakeInstance() const; + /** + * Get all the source files this makefile knows about + */ + const std::vector<cmSourceFile*> &GetSourceFiles() const + {return m_SourceFiles;} + std::vector<cmSourceFile*> &GetSourceFiles() {return m_SourceFiles;} + + /** + * Is there a source file that has the provided source file as an output? + * if so then return it + */ + cmSourceFile *GetSourceFileWithOutput(const char *outName); + protected: // add link libraries and directories to the target void AddGlobalLinkInformation(const char* name, cmTarget& target); diff --git a/Source/cmSetSourceFilesPropertiesCommand.cxx b/Source/cmSetSourceFilesPropertiesCommand.cxx index e57cfa6..65e85fe 100644 --- a/Source/cmSetSourceFilesPropertiesCommand.cxx +++ b/Source/cmSetSourceFilesPropertiesCommand.cxx @@ -29,6 +29,7 @@ bool cmSetSourceFilesPropertiesCommand::InitialPass( // first collect up the list of files std::vector<std::string> propertyPairs; bool doingFiles = true; + bool generated = false; int numFiles = 0; std::vector<std::string>::const_iterator j; for(j= args.begin(); j != args.end();++j) @@ -49,6 +50,7 @@ bool cmSetSourceFilesPropertiesCommand::InitialPass( else if(*j == "GENERATED") { doingFiles = false; + generated = true; propertyPairs.push_back("GENERATED"); propertyPairs.push_back("1"); } @@ -84,7 +86,18 @@ bool cmSetSourceFilesPropertiesCommand::InitialPass( while (j != args.end()) { propertyPairs.push_back(*j); - ++j; + if(*j == "GENERATED") + { + ++j; + if(j != args.end() && cmSystemTools::IsOn(j->c_str())) + { + generated = true; + } + } + else + { + ++j; + } if(j == args.end()) { this->SetError("called with incorrect number of arguments."); @@ -112,67 +125,13 @@ bool cmSetSourceFilesPropertiesCommand::InitialPass( unsigned int k; for(i = 0; i < numFiles; ++i) { - // if the file is already in the makefile just set properites on it - cmSourceFile* sf = m_Makefile->GetSource(args[i].c_str()); - if(sf) + // get the source file + cmSourceFile* sf = + m_Makefile->GetOrCreateSource(args[i].c_str(), generated); + // now loop through all the props and set them + for (k = 0; k < propertyPairs.size(); k = k + 2) { - // now loop through all the props and set them - for (k = 0; k < propertyPairs.size(); k = k + 2) - { - sf->SetProperty(propertyPairs[k].c_str(),propertyPairs[k+1].c_str()); - } - } - // if file is not already in the makefile, then add it - else - { - std::string newfile = args[i]; - cmSourceFile file; - std::string path = cmSystemTools::GetFilenamePath(newfile); - // now loop through all the props and set them - for (k = 0; k < propertyPairs.size(); k = k + 2) - { - file.SetProperty(propertyPairs[k].c_str(),propertyPairs[k+1].c_str()); - } - if(file.GetPropertyAsBool("GENERATED")) - { - std::string ext = cmSystemTools::GetFilenameExtension(newfile); - std::string name_no_ext = cmSystemTools::GetFilenameName(newfile.c_str()); - name_no_ext = name_no_ext.substr(0, name_no_ext.length()-ext.length()); - if ( ext.length() && ext[0] == '.' ) - { - ext = ext.substr(1); - } - if((path.size() && path[0] == '/') || - (path.size() > 1 && path[1] == ':')) - { - file.SetName(name_no_ext.c_str(), path.c_str(), ext.c_str(), false); - } - else - { - file.SetName(name_no_ext.c_str(), m_Makefile->GetCurrentOutputDirectory(), - ext.c_str(), false); - } - } - else - { - // if this is a full path then - if((path.size() && path[0] == '/') || - (path.size() > 1 && path[1] == ':')) - { - file.SetName(cmSystemTools::GetFilenameName(newfile.c_str()).c_str(), - path.c_str(), - m_Makefile->GetSourceExtensions(), - m_Makefile->GetHeaderExtensions()); - } - else - { - file.SetName(newfile.c_str(), m_Makefile->GetCurrentDirectory(), - m_Makefile->GetSourceExtensions(), - m_Makefile->GetHeaderExtensions()); - } - } - // add the source file to the makefile - m_Makefile->AddSource(file); + sf->SetProperty(propertyPairs[k].c_str(),propertyPairs[k+1].c_str()); } } return true; diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h index e04a856..d6d1744 100644 --- a/Source/cmSourceFile.h +++ b/Source/cmSourceFile.h @@ -18,6 +18,7 @@ #define cmSourceFile_h #include "cmStandardIncludes.h" +#include "cmCustomCommand.h" /** \class cmSourceFile * \brief Represent a class loaded from a makefile. @@ -34,6 +35,11 @@ public: */ cmSourceFile() { + m_CustomCommand = 0; + } + ~cmSourceFile() + { + if (m_CustomCommand) { delete m_CustomCommand; } } /** @@ -46,6 +52,15 @@ public: const std::vector<std::string>& headerExts); /** + * Get the list of the custom commands for this source file + */ + const cmCustomCommand *GetCustomCommand() const + {return m_CustomCommand;} + cmCustomCommand *GetCustomCommand() {return m_CustomCommand;} + void SetCustomCommand(cmCustomCommand *cc) + { m_CustomCommand = cc;} + + /** * Set the name of the file, given the directory the file should be in. IN * this version the extension is provided in the call. This is useful for * generated files that do not exist prior to the build. @@ -77,8 +92,7 @@ public: void SetSourceName(const char *name) {m_SourceName = name;} /** - * The file name associated with stripped off directory and extension. - * (In most cases this is the name of the class.) + * The file extension associated with source file */ const std::string &GetSourceExtension() const {return m_SourceExtension;} void SetSourceExtension(const char *name) {m_SourceExtension = name;} @@ -90,8 +104,8 @@ public: std::vector<std::string> &GetDepends() {return m_Depends;} private: - std::map<cmStdString,cmStdString> m_Properties; + cmCustomCommand *m_CustomCommand; std::string m_FullPath; std::string m_SourceName; std::string m_SourceExtension; diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx index 081f299..8815e30 100644 --- a/Source/cmSourceGroup.cxx +++ b/Source/cmSourceGroup.cxx @@ -33,7 +33,7 @@ cmSourceGroup::cmSourceGroup(const char* name, const char* regex): cmSourceGroup::cmSourceGroup(const cmSourceGroup& r): m_Name(r.m_Name), m_GroupRegex(r.m_GroupRegex), - m_BuildRules(r.m_BuildRules) + m_SourceFiles(r.m_SourceFiles) { } @@ -52,100 +52,6 @@ bool cmSourceGroup::Matches(const char* name) */ void cmSourceGroup::AddSource(const char* name, const cmSourceFile* sf) { - BuildRules::iterator s = m_BuildRules.find(name); - if(s == m_BuildRules.end()) - { - SourceAndCommands sc; - sc.m_SourceFile = sf; - // The source was not found. Add it with no commands. - m_BuildRules[name] = sc; - return; - } + m_SourceFiles.push_back(sf); } - -/** - * Add a source and corresponding custom command to the group. If the - * source already exists, the command will be added to its set of commands. - * If the command also already exists, the given dependencies and outputs - * are added to it. - */ -void cmSourceGroup::AddCustomCommand(const cmCustomCommand &cmd) -{ - std::string commandAndArgs = cmd.GetCommandAndArguments(); - BuildRules::iterator s = m_BuildRules.find(cmd.GetSourceName()); - if(s == m_BuildRules.end()) - { - // The source was not found. Add it with this command. - CommandFiles& cmdFiles = - m_BuildRules[cmd.GetSourceName()].m_Commands[commandAndArgs]; - cmdFiles.m_Command = cmd.GetCommand(); - cmdFiles.m_Comment = cmd.GetComment(); - cmdFiles.m_Arguments = cmd.GetArguments(); - cmdFiles.m_Depends.insert(cmd.GetDepends().begin(),cmd.GetDepends().end()); - cmdFiles.m_Outputs.insert(cmd.GetOutputs().begin(),cmd.GetOutputs().end()); - return; - } - - // The source already exists. See if the command exists. - Commands& commands = s->second.m_Commands; - Commands::iterator c = commands.find(commandAndArgs); - if(c == commands.end()) - { - // The command did not exist. Add it. - commands[commandAndArgs].m_Command = cmd.GetCommand(); - commands[commandAndArgs].m_Comment = cmd.GetComment(); - commands[commandAndArgs].m_Arguments = cmd.GetArguments(); - commands[commandAndArgs].m_Depends.insert(cmd.GetDepends().begin(), - cmd.GetDepends().end()); - commands[commandAndArgs].m_Outputs.insert(cmd.GetOutputs().begin(), - cmd.GetOutputs().end()); - return; - } - - // The command already exists for this source. Merge the sets. - CommandFiles& commandFiles = c->second; - commandFiles.m_Depends.insert(cmd.GetDepends().begin(), - cmd.GetDepends().end()); - commandFiles.m_Outputs.insert(cmd.GetOutputs().begin(), - cmd.GetOutputs().end()); -} - -void cmSourceGroup::Print() const -{ - std::cout << "cmSourceGroup: " << m_Name.c_str() << "\n"; - for(BuildRules::const_iterator i = m_BuildRules.begin(); - i != m_BuildRules.end(); ++i) - { - std::cout << "BuildRule: " << i->first.c_str() << "\n"; - for(Commands::const_iterator j = i->second.m_Commands.begin(); - j != i->second.m_Commands.end(); ++j) - { - std::cout << "FullCommand: " << j->first.c_str() << "\n"; - std::cout << "Command: " << j->second.m_Command.c_str() << "\n"; - std::cout << "Arguments: " << j->second.m_Arguments.c_str() << "\n"; - std::cout << "Command Outputs " - << static_cast<int>(j->second.m_Outputs.size()) << "\n"; - std::cout << "Command Depends " - << static_cast<int>(j->second.m_Depends.size()) << "\n"; - } - } -} - - -void cmSourceGroup::CommandFiles::Merge(const CommandFiles &r) -{ - std::set<std::string>::const_iterator dep = r.m_Depends.begin(); - std::set<std::string>::const_iterator out = r.m_Outputs.begin(); - for (;dep != r.m_Depends.end(); ++dep) - { - this->m_Depends.insert(*dep); - } - for (;out != r.m_Outputs.end(); ++out) - { - this->m_Outputs.insert(*out); - } -} - - - diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h index 6c3fe4d..0dbd8cc 100644 --- a/Source/cmSourceGroup.h +++ b/Source/cmSourceGroup.h @@ -19,7 +19,6 @@ #include "cmStandardIncludes.h" #include "cmRegularExpression.h" -#include "cmCustomCommand.h" class cmSourceFile; /** \class cmSourceGroup @@ -35,47 +34,20 @@ public: cmSourceGroup(const cmSourceGroup&); ~cmSourceGroup() {} - struct CommandFiles - { - CommandFiles() {} - CommandFiles(const CommandFiles& r): - m_Comment(r.m_Comment), m_Outputs(r.m_Outputs), m_Depends(r.m_Depends) {} - - void Merge(const CommandFiles &r); - - std::string m_Command; - std::string m_Arguments; - std::string m_Comment; - std::set<std::string> m_Outputs; - std::set<std::string> m_Depends; - }; - - /** - * Map from command to its output/depends sets. - */ - typedef std::map<cmStdString, CommandFiles> Commands; - - struct SourceAndCommands - { - SourceAndCommands(): m_SourceFile(0) {} - const cmSourceFile* m_SourceFile; - Commands m_Commands; - }; - /** - * Map from source to command map. - */ - typedef std::map<cmStdString, SourceAndCommands> BuildRules; - - bool Matches(const char* name); void SetGroupRegex(const char* regex) { m_GroupRegex.compile(regex); } void AddSource(const char* name, const cmSourceFile*); - void AddCustomCommand(const cmCustomCommand &cmd); const char* GetName() const { return m_Name.c_str(); } - const BuildRules& GetBuildRules() const - { return m_BuildRules; } - void Print() const; + bool Matches(const char *); + + /** + * Get the list of the source files used by this target + */ + const std::vector<const cmSourceFile*> &GetSourceFiles() const + {return m_SourceFiles;} + std::vector<const cmSourceFile*> &GetSourceFiles() {return m_SourceFiles;} + private: /** * The name of the source group. @@ -88,11 +60,9 @@ private: cmRegularExpression m_GroupRegex; /** - * Map from source name to the commands to build from the source. - * Some commands may build from files that the compiler also knows how to - * build. + * vector of all source files in this source group */ - BuildRules m_BuildRules; + std::vector<const cmSourceFile*> m_SourceFiles; }; #endif diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 46bcabd..0ef39fd 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1932,6 +1932,25 @@ std::string cmSystemTools::GetFilenameExtension(const std::string& filename) } } +/** + * Return file extension of a full filename (dot included). + * Warning: this is the shortest extension (for example: .tar.gz) + */ +std::string +cmSystemTools::GetFilenameLastExtension(const std::string& filename) +{ + std::string name = cmSystemTools::GetFilenameName(filename); + std::string::size_type dot_pos = name.rfind("."); + if(dot_pos != std::string::npos) + { + return name.substr(dot_pos); + } + else + { + return ""; + } +} + /** * Return file name without extension of a full filename (i.e. without path). diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 24ac737..8317e64 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -284,6 +284,9 @@ public: ///! return file extension of a full filename (dot included). static std::string GetFilenameExtension(const std::string&); + ///! return file extension of a full filename (dot included). + static std::string GetFilenameLastExtension(const std::string&); + ///! return file name without extension of a full filename. static std::string GetFilenameWithoutExtension(const std::string&); diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 14ee770..89dac6a 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -34,6 +34,8 @@ public: SHARED_LIBRARY, MODULE_LIBRARY, UTILITY, INSTALL_FILES, INSTALL_PROGRAMS }; + enum CustomCommandType { PRE_BUILD, PRE_LINK, POST_BUILD }; + /** * Return the type of target. */ @@ -57,8 +59,18 @@ public: /** * Get the list of the custom commands for this target */ - const std::vector<cmCustomCommand> &GetCustomCommands() const {return m_CustomCommands;} - std::vector<cmCustomCommand> &GetCustomCommands() {return m_CustomCommands;} + const std::vector<cmCustomCommand> &GetPreBuildCommands() const + {return m_PreBuildCommands;} + std::vector<cmCustomCommand> &GetPreBuildCommands() + {return m_PreBuildCommands;} + const std::vector<cmCustomCommand> &GetPreLinkCommands() const + {return m_PreLinkCommands;} + std::vector<cmCustomCommand> &GetPreLinkCommands() + {return m_PreLinkCommands;} + const std::vector<cmCustomCommand> &GetPostBuildCommands() const + {return m_PostBuildCommands;} + std::vector<cmCustomCommand> &GetPostBuildCommands() + {return m_PostBuildCommands;} /** * Get the list of the source lists used by this target @@ -186,7 +198,9 @@ private: private: - std::vector<cmCustomCommand> m_CustomCommands; + std::vector<cmCustomCommand> m_PreBuildCommands; + std::vector<cmCustomCommand> m_PreLinkCommands; + std::vector<cmCustomCommand> m_PostBuildCommands; std::vector<std::string> m_SourceLists; TargetType m_TargetType; std::vector<cmSourceFile*> m_SourceFiles; |