diff options
author | Brad King <brad.king@kitware.com> | 2004-10-27 12:20:58 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2004-10-27 12:20:58 (GMT) |
commit | 414a2fd645867058ca50cc6a8eed260d13ad1749 (patch) | |
tree | ff0b6b5b06d85a98b54d90e86a5a30b15686f940 /Source/cmLocalUnixMakefileGenerator2.cxx | |
parent | 5c168174f7430acf59aa66c2690d6da347fdb0f2 (diff) | |
download | CMake-414a2fd645867058ca50cc6a8eed260d13ad1749.zip CMake-414a2fd645867058ca50cc6a8eed260d13ad1749.tar.gz CMake-414a2fd645867058ca50cc6a8eed260d13ad1749.tar.bz2 |
ENH: Added rules to build executables. Also began to consolidate flag list construction into separate methods.
Diffstat (limited to 'Source/cmLocalUnixMakefileGenerator2.cxx')
-rw-r--r-- | Source/cmLocalUnixMakefileGenerator2.cxx | 532 |
1 files changed, 437 insertions, 95 deletions
diff --git a/Source/cmLocalUnixMakefileGenerator2.cxx b/Source/cmLocalUnixMakefileGenerator2.cxx index cbb67cd..46cbf8f 100644 --- a/Source/cmLocalUnixMakefileGenerator2.cxx +++ b/Source/cmLocalUnixMakefileGenerator2.cxx @@ -257,11 +257,8 @@ cmLocalUnixMakefileGenerator2 // Generate this object file's rule file. this->GenerateObjectRuleFile(target, *(*source)); - // Save the object file full path. - std::string obj = dir; - obj += "/"; - obj += this->GetObjectFileName(*(*source)); - objects.push_back(obj); + // Save the object file name. + objects.push_back(this->GetObjectFileName(target, *(*source))); } } @@ -343,6 +340,7 @@ cmLocalUnixMakefileGenerator2 depends, commands); } +#if 0 // Write the requires rule. { std::vector<std::string> depends; @@ -360,28 +358,22 @@ cmLocalUnixMakefileGenerator2 this->OutputMakeRule(ruleFileStream, reqComment.c_str(), reqTarget.c_str(), depends, commands); } +#endif -#if 0 // Write the build rule. - { - std::vector<std::string> depends; - std::vector<std::string> commands; - std::string buildComment = " target "; - buildComment += objName; - for(std::vector<std::string>::const_iterator obj = objects.begin(); - obj != objects.end(); ++obj) + switch(target.GetType()) { - depends.push_back(*obj); + case cmTarget::STATIC_LIBRARY: + this->WriteStaticLibraryRule(ruleFileStream, ruleFileName.c_str(), + target, objects); + break; + case cmTarget::EXECUTABLE: + this->WriteExecutableRule(ruleFileStream, ruleFileName.c_str(), + target, objects); + break; + default: + break; } - depends.push_back(ruleFileName); - std::string touchCmd = "@touch "; - touchCmd += this->ConvertToRelativeOutputPath(obj.c_str()); - // TODO: Construct build rule and append command. - commands.push_back(touchCmd); - this->OutputMakeRule(ruleFileStream, buildComment.c_str(), obj.c_str(), - depends, commands); - } -#endif } //---------------------------------------------------------------------------- @@ -400,10 +392,7 @@ cmLocalUnixMakefileGenerator2 } // Get the full path name of the object file. - std::string objName = this->GetObjectFileName(source); - std::string obj = this->GetTargetDirectory(target); - obj += "/"; - obj += objName; + std::string obj = this->GetObjectFileName(target, source); // Create the directory containing the object file. This may be a // subdirectory under the target's directory. @@ -418,8 +407,7 @@ cmLocalUnixMakefileGenerator2 std::ofstream depFileStream(depFileName.c_str()); this->WriteDisclaimer(depFileStream); depFileStream - << "# Empty dependencies file for object file " - << objName.c_str() << ".\n" + << "# Empty dependencies file for object file " << obj.c_str() << ".\n" << "# This may be replaced when dependencies are built.\n"; } @@ -437,7 +425,7 @@ cmLocalUnixMakefileGenerator2 } this->WriteDisclaimer(ruleFileStream); ruleFileStream - << "# Rule file for object file " << objName.c_str() << ".\n\n"; + << "# Rule file for object file " << obj.c_str() << ".\n\n"; // Include the dependencies for the target. ruleFileStream @@ -467,7 +455,7 @@ cmLocalUnixMakefileGenerator2 depTarget += ".depends"; { std::string depComment = "dependencies for "; - depComment += objName; + depComment += obj; cmOStringStream depCmd; // TODO: Account for source file properties and directory-level // definitions when scanning for dependencies. @@ -514,71 +502,16 @@ cmLocalUnixMakefileGenerator2 } // Add flags from source file properties. - if(const char* compileFlags = source.GetProperty("COMPILE_FLAGS")) - { - flags += " "; - flags += compileFlags; - } + this->AppendFlags(flags, source.GetProperty("COMPILE_FLAGS")); // Add language-specific flags. - std::string langFlagsVar = "CMAKE_"; - langFlagsVar += lang; - langFlagsVar += "_FLAGS"; - const char* langFlags = m_Makefile->GetSafeDefinition(langFlagsVar.c_str()); - if(*langFlags) - { - flags += " "; - flags += langFlags; - } - std::string buildType = m_Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); - if(buildType.size()) - { - buildType = cmSystemTools::UpperCase(buildType); - langFlagsVar += "_"; - langFlagsVar += buildType; - langFlags = m_Makefile->GetSafeDefinition(langFlagsVar.c_str()); - if(*langFlags) - { - flags += " "; - flags += langFlags; - } - } + this->AddLanguageFlags(flags, lang); // Add shared-library flags if needed. - if(shared) - { - std::string sharedFlagsVar = "CMAKE_SHARED_LIBRARY_"; - sharedFlagsVar += lang; - sharedFlagsVar += "_FLAGS"; - const char* sharedFlags = - m_Makefile->GetSafeDefinition(sharedFlagsVar.c_str()); - if(*sharedFlags) - { - flags += " "; - flags += sharedFlags; - } - } - if(cmSystemTools::IsOn(m_Makefile->GetDefinition("BUILD_SHARED_LIBS"))) - { - std::string sharedFlagsVar = "CMAKE_SHARED_BUILD_"; - sharedFlagsVar += lang; - sharedFlagsVar += "_FLAGS"; - const char* sharedFlags = - m_Makefile->GetSafeDefinition(sharedFlagsVar.c_str()); - if(*sharedFlags) - { - flags += " "; - flags += sharedFlags; - } - } + this->AddSharedFlags(flags, lang, shared); // Add include directory flags. - const char* includeFlags = this->GetIncludeFlags(lang); - if(includeFlags && *includeFlags) - { - flags += " "; - flags += includeFlags; - } + this->AppendFlags(flags, this->GetIncludeFlags(lang)); // Get the output paths for source and object files. std::string sourceFile = @@ -594,6 +527,8 @@ cmLocalUnixMakefileGenerator2 std::string compileRule = m_Makefile->GetRequiredDefinition(compileRuleVar.c_str()); cmSystemTools::ExpandListArgument(compileRule, commands); + + // Expand placeholders in the commands. for(std::vector<std::string>::iterator i = commands.begin(); i != commands.end(); ++i) { @@ -627,13 +562,344 @@ void cmLocalUnixMakefileGenerator2::WriteDisclaimer(std::ostream& os) } //---------------------------------------------------------------------------- +void +cmLocalUnixMakefileGenerator2 +::WriteExecutableRule(std::ostream& ruleFileStream, + const char* ruleFileName, + const cmTarget& target, + std::vector<std::string>& objects) +{ + std::vector<std::string> commands; + + // Build list of dependencies. TODO: depend on other targets. + std::vector<std::string> depends; + for(std::vector<std::string>::const_iterator obj = objects.begin(); + obj != objects.end(); ++obj) + { + depends.push_back(*obj); + } + depends.push_back(ruleFileName); + + // Construct the full path to the executable that will be generated. + std::string targetFullPath = m_ExecutableOutputPath; + if(targetFullPath.length() == 0) + { + targetFullPath = m_Makefile->GetCurrentOutputDirectory(); + if(targetFullPath.size() && targetFullPath[targetFullPath.size()-1] != '/') + { + targetFullPath += "/"; + } + } +#ifdef __APPLE__ + if(target.GetPropertyAsBool("MACOSX_BUNDLE")) + { + // Make bundle directories + targetFullPath += name; + targetFullPath += ".app/Contents/MacOS/"; + } +#endif + targetFullPath += target.GetName(); + targetFullPath += cmSystemTools::GetExecutableExtension(); + targetFullPath = this->ConvertToRelativeOutputPath(targetFullPath.c_str()); + + // Get the language to use for linking this executable. + const char* linkLanguage = + target.GetLinkerLanguage(this->GetGlobalGenerator()); + + // Build a list of linker flags. + std::string linkFlags; + + // Add flags to create an executable. + this->AddConfigVariableFlags(linkFlags, "CMAKE_EXE_LINKER_FLAGS"); + if(target.GetPropertyAsBool("WIN32_EXECUTABLE")) + { + this->AppendFlags(linkFlags, + m_Makefile->GetDefinition("CMAKE_CREATE_WIN32_EXE")); + } + else + { + this->AppendFlags(linkFlags, + m_Makefile->GetDefinition("CMAKE_CREATE_CONSOLE_EXE")); + } + + // Add language-specific flags. + this->AddLanguageFlags(linkFlags, linkLanguage); + + // Add flags to deal with shared libraries. Any library being + // linked in might be shared, so always use shared flags for an + // executable. + this->AddSharedFlags(linkFlags, linkLanguage, true); + + // Add target-specific flags. + this->AppendFlags(linkFlags, target.GetProperty("LINK_FLAGS")); + + // TODO: Pre-build and pre-link rules. + + // Construct the main link rule. + std::string linkRuleVar = "CMAKE_"; + linkRuleVar += linkLanguage; + linkRuleVar += "_LINK_EXECUTABLE"; + std::string linkRule = m_Makefile->GetRequiredDefinition(linkRuleVar.c_str()); + cmSystemTools::ExpandListArgument(linkRule, commands); + + // TODO: Post-build rules. + + // Collect up flags to link in needed libraries. + cmOStringStream linklibs; + this->OutputLinkLibraries(linklibs, 0, target); + + // Construct object file lists that may be needed to expand the + // rule. TODO: Store these in make variables with line continuation + // to avoid excessively long lines. + std::string objs; + std::string objsQuoted; + const char* space = ""; + for(std::vector<std::string>::iterator i = objects.begin(); + i != objects.end(); ++i) + { + objs += space; + objs += *i; + objsQuoted += space; + objsQuoted += "\""; + objsQuoted += *i; + objsQuoted += "\""; + space = " "; + } + + // Expand placeholders in the commands. + for(std::vector<std::string>::iterator i = commands.begin(); + i != commands.end(); ++i) + { + this->ExpandRuleVariables(*i, + linkLanguage, + objs.c_str(), + targetFullPath.c_str(), + linklibs.str().c_str(), + 0, + 0, + /*flags.c_str() why?*/ "", + 0, + 0, + 0, + linkFlags.c_str()); + } + + // Write the build rule. + std::string buildComment = linkLanguage; + buildComment += " executable"; + this->OutputMakeRule(ruleFileStream, buildComment.c_str(), + targetFullPath.c_str(), + depends, commands); + // TODO: Add "local" target and canonical target name as rules. + + // Write the requires rule. + { + std::vector<std::string> depends; + std::vector<std::string> commands; + std::string reqComment = "requirements for "; + reqComment += target.GetName(); + std::string reqTarget = target.GetName(); + reqTarget += ".requires"; + depends.push_back(targetFullPath); + this->OutputMakeRule(ruleFileStream, reqComment.c_str(), reqTarget.c_str(), + depends, commands); + } +} + +//---------------------------------------------------------------------------- +void +cmLocalUnixMakefileGenerator2 +::WriteStaticLibraryRule(std::ostream& ruleFileStream, + const char* ruleFileName, + const cmTarget& target, + std::vector<std::string>& objects) +{ + const char* linkLanguage = + target.GetLinkerLanguage(this->GetGlobalGenerator()); + std::string linkRuleVar = "CMAKE_"; + linkRuleVar += linkLanguage; + linkRuleVar += "_CREATE_STATIC_LIBRARY"; + this->WriteLibraryRule(ruleFileStream, ruleFileName, target, objects, + linkRuleVar.c_str(), "STATIC_LIBRARY_FLAGS"); +} + +//---------------------------------------------------------------------------- +void +cmLocalUnixMakefileGenerator2 +::WriteLibraryRule(std::ostream& ruleFileStream, + const char* ruleFileName, + const cmTarget& target, + std::vector<std::string>& objects, + const char* linkRuleVar, + const char* flagsPropertyName) +{ + std::vector<std::string> commands; + + // Build list of dependencies. TODO: depend on other targets. + std::vector<std::string> depends; + for(std::vector<std::string>::const_iterator obj = objects.begin(); + obj != objects.end(); ++obj) + { + depends.push_back(*obj); + } + depends.push_back(ruleFileName); + + const char* linkLanguage = + target.GetLinkerLanguage(this->GetGlobalGenerator()); + std::string linkFlags; + if(const char* targetLinkFlags = target.GetProperty(flagsPropertyName)) + { + linkFlags += " "; + linkFlags += targetLinkFlags; + } + std::string targetName; + std::string targetNameSO; + std::string targetNameReal; + std::string targetNameBase; + this->GetLibraryNames(target.GetName(), target, + targetName, targetNameSO, + targetNameReal, targetNameBase); + + std::string outpath; + std::string outdir; + if(m_UseRelativePaths) + { + outdir = this->ConvertToRelativeOutputPath(m_LibraryOutputPath.c_str()); + } + else + { + outdir = m_LibraryOutputPath; + } + if(!m_WindowsShell && m_UseRelativePaths && outdir.size()) + { + outpath = "\"`cd "; + } + outpath += outdir; + if(!m_WindowsShell && m_UseRelativePaths && outdir.size()) + { + outpath += ";pwd`\"/"; + } + if(outdir.size() == 0 && m_UseRelativePaths && !m_WindowsShell) + { + outpath = "\"`pwd`\"/"; + } + // The full path versions of the names. + std::string targetFullPath = outpath + targetName; + std::string targetFullPathSO = outpath + targetNameSO; + std::string targetFullPathReal = outpath + targetNameReal; + std::string targetFullPathBase = outpath + targetNameBase; + // If not using relative paths then the output path needs to be + // converted here + if(!m_UseRelativePaths) + { + targetFullPath = this->ConvertToRelativeOutputPath(targetFullPath.c_str()); + targetFullPathSO = this->ConvertToRelativeOutputPath(targetFullPathSO.c_str()); + targetFullPathReal = this->ConvertToRelativeOutputPath(targetFullPathReal.c_str()); + targetFullPathBase = this->ConvertToRelativeOutputPath(targetFullPathBase.c_str()); + } + + // Add a command to remove any existing files for this library. + std::string remove = "$(CMAKE_COMMAND) -E remove -f "; + remove += targetFullPathReal; + if(targetFullPathSO != targetFullPathReal) + { + remove += " "; + remove += targetFullPathSO; + } + if(targetFullPath != targetFullPathSO && + targetFullPath != targetFullPathReal) + { + remove += " "; + remove += targetFullPath; + } + commands.push_back(remove); + + // TODO: Pre-build and pre-link rules. + + // Construct the main link rule. + std::string linkRule = m_Makefile->GetRequiredDefinition(linkRuleVar); + cmSystemTools::ExpandListArgument(linkRule, commands); + + // Add a rule to create necessary symlinks for the library. + if(targetFullPath != targetFullPathReal) + { + std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_library "; + symlink += targetFullPathReal; + symlink += " "; + symlink += targetFullPathSO; + symlink += " "; + symlink += targetFullPath; + commands.push_back(symlink); + } + + // TODO: Post-build rules. + + // Collect up flags to link in needed libraries. + cmOStringStream linklibs; + this->OutputLinkLibraries(linklibs, target.GetName(), target); + + // Construct object file lists that may be needed to expand the + // rule. TODO: Store these in make variables with line continuation + // to avoid excessively long lines. + std::string objs; + std::string objsQuoted; + const char* space = ""; + for(std::vector<std::string>::iterator i = objects.begin(); + i != objects.end(); ++i) + { + objs += space; + objs += *i; + objsQuoted += space; + objsQuoted += "\""; + objsQuoted += *i; + objsQuoted += "\""; + space = " "; + } + + // Expand placeholders in the commands. + for(std::vector<std::string>::iterator i = commands.begin(); + i != commands.end(); ++i) + { + this->ExpandRuleVariables(*i, + linkLanguage, + objs.c_str(), + targetFullPathReal.c_str(), + linklibs.str().c_str(), + 0, 0, 0, objsQuoted.c_str(), + targetFullPathBase.c_str(), + targetNameSO.c_str(), + linkFlags.c_str()); + } + + // Write the build rule. + std::string buildComment = linkLanguage; + buildComment += " static library"; + this->OutputMakeRule(ruleFileStream, buildComment.c_str(), + targetFullPath.c_str(), + depends, commands); + + // TODO: Add "local" target and canonical target name as rules. + + // Write the requires rule. + { + std::vector<std::string> depends; + std::vector<std::string> commands; + std::string reqComment = "requirements for "; + reqComment += target.GetName(); + std::string reqTarget = target.GetName(); + reqTarget += ".requires"; + depends.push_back(targetFullPath); + this->OutputMakeRule(ruleFileStream, reqComment.c_str(), reqTarget.c_str(), + depends, commands); + } +} + +//---------------------------------------------------------------------------- std::string cmLocalUnixMakefileGenerator2 ::GetTargetDirectory(const cmTarget& target) { - std::string dir = m_Makefile->GetStartOutputDirectory(); - dir += "/"; - dir += target.GetName(); + std::string dir = target.GetName(); dir += ".dir"; return dir; } @@ -641,7 +907,8 @@ cmLocalUnixMakefileGenerator2 //---------------------------------------------------------------------------- std::string cmLocalUnixMakefileGenerator2 -::GetObjectFileName(const cmSourceFile& source) +::GetObjectFileName(const cmTarget& target, + const cmSourceFile& source) { // If the full path to the source file includes this directory, // we want to use the relative path for the filename of the @@ -668,7 +935,13 @@ cmLocalUnixMakefileGenerator2 source.GetSourceExtension().c_str()); // Convert to a safe name. - return this->CreateSafeUniqueObjectFileName(objectName.c_str()); + objectName = this->CreateSafeUniqueObjectFileName(objectName.c_str()); + + // Prepend the target directory. + std::string obj = this->GetTargetDirectory(target); + obj += "/"; + obj += objectName; + return obj; } //---------------------------------------------------------------------------- @@ -682,6 +955,75 @@ cmLocalUnixMakefileGenerator2 } //---------------------------------------------------------------------------- +void cmLocalUnixMakefileGenerator2::AddLanguageFlags(std::string& flags, + const char* lang) +{ + // Add language-specific flags. + std::string flagsVar = "CMAKE_"; + flagsVar += lang; + flagsVar += "_FLAGS"; + this->AddConfigVariableFlags(flags, flagsVar.c_str()); +} + +//---------------------------------------------------------------------------- +void cmLocalUnixMakefileGenerator2::AddSharedFlags(std::string& flags, + const char* lang, + bool shared) +{ + std::string flagsVar; + + // Add flags for dealing with shared libraries for this language. + if(shared) + { + flagsVar = "CMAKE_SHARED_LIBRARY_"; + flagsVar += lang; + flagsVar += "_FLAGS"; + this->AppendFlags(flags, m_Makefile->GetDefinition(flagsVar.c_str())); + } + + // Add flags specific to shared builds. + if(cmSystemTools::IsOn(m_Makefile->GetDefinition("BUILD_SHARED_LIBS"))) + { + flagsVar = "CMAKE_SHARED_BUILD_"; + flagsVar += lang; + flagsVar += "_FLAGS"; + this->AppendFlags(flags, m_Makefile->GetDefinition(flagsVar.c_str())); + } +} + +//---------------------------------------------------------------------------- +void cmLocalUnixMakefileGenerator2::AddConfigVariableFlags(std::string& flags, + const char* var) +{ + // Add the flags from the variable itself. + std::string flagsVar = var; + this->AppendFlags(flags, m_Makefile->GetDefinition(flagsVar.c_str())); + + // Add the flags from the build-type specific variable. + const char* buildType = m_Makefile->GetDefinition("CMAKE_BUILD_TYPE"); + if(buildType && *buildType) + { + flagsVar += "_"; + flagsVar += cmSystemTools::UpperCase(buildType); + this->AppendFlags(flags, m_Makefile->GetDefinition(flagsVar.c_str())); + } +} + +//---------------------------------------------------------------------------- +void cmLocalUnixMakefileGenerator2::AppendFlags(std::string& flags, + const char* newFlags) +{ + if(newFlags && *newFlags) + { + if(flags.size()) + { + flags += " "; + } + flags += newFlags; + } +} + +//---------------------------------------------------------------------------- bool cmLocalUnixMakefileGenerator2 ::ScanDependencies(std::vector<std::string> const& args) |