diff options
author | Bill Hoffman <bill.hoffman@kitware.com> | 2004-10-21 18:34:02 (GMT) |
---|---|---|
committer | Bill Hoffman <bill.hoffman@kitware.com> | 2004-10-21 18:34:02 (GMT) |
commit | 7cef36c628a8ef07a0c53ea08691e4e6b949a695 (patch) | |
tree | 6dddd32ad310a5a069b66462cc79ca3fea15f024 /Source/cmLocalGenerator.cxx | |
parent | 8ff4c079159a8c5a53017ff1b02c8ac591eb2727 (diff) | |
download | CMake-7cef36c628a8ef07a0c53ea08691e4e6b949a695.zip CMake-7cef36c628a8ef07a0c53ea08691e4e6b949a695.tar.gz CMake-7cef36c628a8ef07a0c53ea08691e4e6b949a695.tar.bz2 |
ENH: add the ability to generate custom commands for a language that is not supported by an IDE
Diffstat (limited to 'Source/cmLocalGenerator.cxx')
-rw-r--r-- | Source/cmLocalGenerator.cxx | 822 |
1 files changed, 800 insertions, 22 deletions
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index fa4f3d8..e91f579 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -19,6 +19,7 @@ #include "cmake.h" #include "cmMakefile.h" #include "cmGeneratedFileStream.h" +#include "cmSourceFile.h" cmLocalGenerator::cmLocalGenerator() { @@ -26,6 +27,9 @@ cmLocalGenerator::cmLocalGenerator() m_Makefile->SetLocalGenerator(this); m_ExcludeFromAll = false; m_Parent = 0; + m_WindowsShell = false; + m_IgnoreLibPrefix = false; + m_UseRelativePaths = false; } cmLocalGenerator::~cmLocalGenerator() @@ -339,32 +343,31 @@ std::string cmLocalGenerator::GetFullTargetName(const char* n, { const char* targetPrefix = t.GetProperty("PREFIX"); const char* targetSuffix = t.GetProperty("SUFFIX"); - const char* prefixVar = 0; - const char* suffixVar = 0; - switch(t.GetType()) - { - case cmTarget::STATIC_LIBRARY: - prefixVar = "CMAKE_STATIC_LIBRARY_PREFIX"; - suffixVar = "CMAKE_STATIC_LIBRARY_SUFFIX"; - break; - case cmTarget::SHARED_LIBRARY: - prefixVar = "CMAKE_SHARED_LIBRARY_PREFIX"; - suffixVar = "CMAKE_SHARED_LIBRARY_SUFFIX"; - break; - case cmTarget::MODULE_LIBRARY: - prefixVar = "CMAKE_SHARED_MODULE_PREFIX"; - suffixVar = "CMAKE_SHARED_MODULE_SUFFIX"; - break; - case cmTarget::EXECUTABLE: + if(!targetSuffix && t.GetType() == cmTarget::EXECUTABLE) + { targetSuffix = cmSystemTools::GetExecutableExtension(); - case cmTarget::UTILITY: - case cmTarget::INSTALL_FILES: - case cmTarget::INSTALL_PROGRAMS: - break; } + const char* prefixVar = t.GetPrefixVariable(); + const char* suffixVar = t.GetSuffixVariable(); + const char* ll = t.GetLinkerLanguage(this->GetGlobalGenerator()); + // first try language specific suffix + if(ll) + { + if(!targetSuffix) + { + std::string langSuff = suffixVar + std::string("_") + ll; + targetSuffix = m_Makefile->GetDefinition(langSuff.c_str()); + } + if(!targetPrefix) + { + std::string langPrefix = prefixVar + std::string("_") + ll; + targetPrefix = m_Makefile->GetDefinition(langPrefix.c_str()); + } + } + // if there is no prefix on the target use the cmake definition if(!targetPrefix && prefixVar) - { + { targetPrefix = m_Makefile->GetSafeDefinition(prefixVar); } // if there is no suffix on the target use the cmake definition @@ -451,5 +454,780 @@ std::string cmLocalGenerator::ConvertToRelativeOutputPath(const char* p) return ret; } +void cmLocalGenerator::AddCustomCommandToCreateObject(const char* ofname, + const char* lang, + cmSourceFile& source, + cmTarget& target) +{ + std::string objectFile = this->ConvertToRelativeOutputPath(ofname); + std::string sourceFile = this->ConvertToRelativeOutputPath(source.GetFullPath().c_str()); + std::string varString = "CMAKE_"; + varString += lang; + varString += "_COMPILE_OBJECT"; + std::vector<std::string> rules; + rules.push_back(m_Makefile->GetRequiredDefinition(varString.c_str())); + varString = "CMAKE_"; + varString += lang; + varString += "_FLAGS"; + std::string flags; + flags += m_Makefile->GetSafeDefinition(varString.c_str()); + flags += " "; + flags += this->GetIncludeFlags(lang); + std::vector<std::string> commands; + cmSystemTools::ExpandList(rules, commands); + for(std::vector<std::string>::iterator i = commands.begin(); + i != commands.end(); ++i) + { + this->ExpandRuleVariables(*i, + lang, + 0, // no objects + 0, // no target + 0, // no link libs + sourceFile.c_str(), + objectFile.c_str(), + flags.c_str()); + } + std::vector<std::string> sourceAndDeps; + sourceAndDeps.push_back(sourceFile); + if(commands.size() > 1) + { + cmSystemTools::Error("Currently custom rules can only have one command sorry "); + } + // Check for extra object-file dependencies. + std::vector<std::string> depends; + const char* additionalDeps = source.GetProperty("OBJECT_DEPENDS"); + if(additionalDeps) + { + cmSystemTools::ExpandListArgument(additionalDeps, depends); + for(std::vector<std::string>::iterator i = depends.begin(); + i != depends.end(); ++i) + { + sourceAndDeps.push_back(this->ConvertToRelativeOutputPath(i->c_str())); + } + } + std::string command; + std::string args; + cmSystemTools::SplitProgramFromArgs(commands[0].c_str(), command, args); + std::vector<std::string> argsv; + argsv.push_back(args); + m_Makefile->AddCustomCommandToOutput(ofname, + command.c_str(), + argsv, + source.GetFullPath().c_str(), + sourceAndDeps, + "build from source"); +} + +void cmLocalGenerator::AddBuildTargetRule(const char* llang, cmTarget& target) +{ + cmStdString objs; + std::vector<std::string> objVector; + // Add all the sources outputs to the depends of the target + std::vector<cmSourceFile*>& classes = target.GetSourceFiles(); + for(std::vector<cmSourceFile*>::iterator i = classes.begin(); + i != classes.end(); ++i) + { + if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY") && + !(*i)->GetCustomCommand()) + { + std::string outExt = + m_GlobalGenerator->GetLanguageOutputExtensionFromExtension( + (*i)->GetSourceExtension().c_str()); + if(outExt.size() && !(*i)->GetPropertyAsBool("EXTERNAL_OBJECT") ) + { + std::string ofname = m_Makefile->GetCurrentOutputDirectory(); + ofname += "/"; + ofname += (*i)->GetSourceName() + outExt; + objVector.push_back(ofname); + this->AddCustomCommandToCreateObject(ofname.c_str(), llang, *(*i), target); + objs += this->ConvertToRelativeOutputPath(ofname.c_str()); + objs += " "; + } + } + } + std::string createRule = "CMAKE_"; + createRule += llang; + createRule += target.GetCreateRuleVariable(); + std::string targetName = this->GetFullTargetName(target.GetName(), target); + // Executable : + // Shared Library: + // Static Library: + // Shared Module: + std::string linkLibs; // should be set + std::string flags; // should be set + std::string linkFlags; // should be set + this->GetTargetFlags(linkLibs, flags, linkFlags, target); + // Change the type to utility +// target.SetType(cmTarget::UTILITY, target.GetName()); + std::string rule = m_Makefile->GetRequiredDefinition(createRule.c_str()); + this->ExpandRuleVariables(rule, + llang, // language + objs.c_str(), // objects + targetName.c_str(), // target + linkLibs.c_str(), // link libs + 0, // source + 0, // object + flags.c_str(), // flags + 0, // objects quoted + 0, // target base name + 0, // target so name, + linkFlags.c_str() // link flags + ); + std::string command; + std::string args; + cmSystemTools::SplitProgramFromArgs(rule.c_str(), command, args); + // Just like ADD_CUSTOM_TARGET(foo ALL DEPENDS a.o b.o) + // Add a custom command for generating each .o file + cmCustomCommand cc(command.c_str(), args.c_str(), objVector, targetName.c_str()); + target.GetPostBuildCommands().push_back(cc); +} +void cmLocalGenerator::CreateCustomTargetsAndCommands(std::set<cmStdString> const& lang) +{ + cmTargets &tgts = m_Makefile->GetTargets(); + for(cmTargets::iterator l = tgts.begin(); + l != tgts.end(); l++) + { + cmTarget& target = l->second; + switch(target.GetType()) + { + case cmTarget::STATIC_LIBRARY: + case cmTarget::SHARED_LIBRARY: + case cmTarget::MODULE_LIBRARY: + case cmTarget::EXECUTABLE: + { + const char* llang = target.GetLinkerLanguage(this->GetGlobalGenerator()); + // if the language is not in the set lang then create custom + // commands to build the target + if(lang.count(llang) == 0) + { + this->AddBuildTargetRule(llang, target); + } + } + break; + } + } +} + + +struct RuleVariables +{ + const char* variable; +}; + + +// List of variables that are replaced when +// rules are expanced. These variables are +// replaced in the form <var> with GetSafeDefinition(var). +// ${LANG} is replaced in the variable first with all enabled +// languages. +static const char* ruleReplaceVars[] = +{ + "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS", + "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS", + "CMAKE_SHARED_MODULE_${LANG}_FLAGS", + "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS", + "CMAKE_${LANG}_LINK_FLAGS", + "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG", + "CMAKE_${LANG}_ARCHIVE", + "CMAKE_${LANG}_COMPILER", + "CMAKE_AR", + "CMAKE_CURRENT_SOURCE_DIR", + "CMAKE_CURRENT_BINARY_DIR", + "CMAKE_RANLIB", + 0 +}; + + + + +void +cmLocalGenerator::ExpandRuleVariables(std::string& s, + const char* lang, + const char* objects, + const char* target, + const char* linkLibs, + const char* source, + const char* object, + const char* flags, + const char* objectsquoted, + const char* targetBase, + const char* targetSOName, + const char* linkFlags) +{ + std::vector<std::string> enabledLanguages; + m_GlobalGenerator->GetEnabledLanguages(enabledLanguages); + + if(linkFlags) + { + cmSystemTools::ReplaceString(s, "<LINK_FLAGS>", linkFlags); + } + if(flags) + { + cmSystemTools::ReplaceString(s, "<FLAGS>", flags); + } + + if(source) + { + cmSystemTools::ReplaceString(s, "<SOURCE>", source); + } + if(object) + { + cmSystemTools::ReplaceString(s, "<OBJECT>", object); + } + if(objects) + { + cmSystemTools::ReplaceString(s, "<OBJECTS>", objects); + } + if(objectsquoted) + { + cmSystemTools::ReplaceString(s, "<OBJECTS_QUOTED>", objectsquoted); + } + if(target) + { + std::string targetQuoted = target; + if(targetQuoted.size() && targetQuoted[0] != '\"') + { + targetQuoted = '\"'; + targetQuoted += target; + targetQuoted += '\"'; + } + cmSystemTools::ReplaceString(s, "<TARGET_QUOTED>", targetQuoted.c_str()); + cmSystemTools::ReplaceString(s, "<TARGET>", target); + } + if(targetBase) + { + // special case for quoted paths with spaces + // if you see <TARGET_BASE>.lib then put the .lib inside + // the quotes, same for .dll + if((strlen(targetBase) > 1) && targetBase[0] == '\"') + { + std::string base = targetBase; + base[base.size()-1] = '.'; + std::string baseLib = base + "lib\""; + std::string baseDll = base + "dll\""; + cmSystemTools::ReplaceString(s, "<TARGET_BASE>.lib", baseLib.c_str()); + cmSystemTools::ReplaceString(s, "<TARGET_BASE>.dll", baseDll.c_str()); + } + cmSystemTools::ReplaceString(s, "<TARGET_BASE>", targetBase); + } + if(targetSOName) + { + bool replaced = false; + if(lang) + { + std::string name = "CMAKE_SHARED_LIBRARY_SONAME_"; + name += lang; + name += "_FLAG"; + if(m_Makefile->GetDefinition(name.c_str())) + { + replaced = true; + cmSystemTools::ReplaceString(s, "<TARGET_SONAME>", targetSOName); + } + } + if(!replaced) + { + cmSystemTools::ReplaceString(s, "<TARGET_SONAME>", ""); + } + } + if(linkLibs) + { + cmSystemTools::ReplaceString(s, "<LINK_LIBRARIES>", linkLibs); + } + + // loop over language specific replace variables + int pos = 0; + while(ruleReplaceVars[pos]) + { + for(std::vector<std::string>::iterator i = enabledLanguages.begin(); + i != enabledLanguages.end(); ++i) + { + lang = i->c_str(); + std::string replace = "<"; + replace += ruleReplaceVars[pos]; + replace += ">"; + std::string replaceWith = ruleReplaceVars[pos]; + std::string actualReplace = replace; + cmSystemTools::ReplaceString(actualReplace, "${LANG}", lang); + std::string actualReplaceWith = replaceWith; + cmSystemTools::ReplaceString(actualReplaceWith, "${LANG}", lang); + replace = m_Makefile->GetSafeDefinition(actualReplaceWith.c_str()); + // if the variable is not a FLAG then treat it like a path + if(actualReplaceWith.find("_FLAG") == actualReplaceWith.npos) + { + replace = this->ConvertToOutputForExisting(replace.c_str()); + } + if(actualReplace.size()) + { + cmSystemTools::ReplaceString(s, actualReplace.c_str(), replace.c_str()); + } + } + pos++; + } +} + + +std::string +cmLocalGenerator::ConvertToOutputForExisting(const char* p) +{ + std::string ret = this->ConvertToRelativeOutputPath(p); + // if there are spaces in the path, then get the short path version + // if there is one + if(ret.find(' ') != std::string::npos) + { + if(cmSystemTools::FileExists(p)) + { + if(!cmSystemTools::GetShortPath(ret.c_str(), ret)) + { + ret = this->ConvertToRelativeOutputPath(p); + } + } + } + return ret; +} + +const char* cmLocalGenerator::GetIncludeFlags(const char* lang) +{ + if(!lang) + { + return ""; + } + if(m_LanguageToIncludeFlags.count(lang)) + { + return m_LanguageToIncludeFlags[lang].c_str(); + } + // Output Include paths + cmOStringStream includeFlags; + std::vector<std::string>& includes = m_Makefile->GetIncludeDirectories(); + std::vector<std::string>::iterator i; + std::map<cmStdString, cmStdString> implicitIncludes; + + // CMake versions below 2.0 would add the source tree to the -I path + // automatically. Preserve compatibility. + bool includeSourceDir = false; + const char* versionValue = + m_Makefile->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY"); + if(versionValue) + { + int major = 0; + int minor = 0; + if(sscanf(versionValue, "%d.%d", &major, &minor) == 2 && major < 2) + { + includeSourceDir = true; + } + } + const char* vtkSourceDir = + m_Makefile->GetDefinition("VTK_SOURCE_DIR"); + if(vtkSourceDir) + { + // Special hack for VTK 4.0 - 4.4. + const char* vtk_major = m_Makefile->GetDefinition("VTK_MAJOR_VERSION"); + const char* vtk_minor = m_Makefile->GetDefinition("VTK_MINOR_VERSION"); + vtk_major = vtk_major? vtk_major : "4"; + vtk_minor = vtk_minor? vtk_minor : "4"; + int major = 0; + int minor = 0; + if(sscanf(vtk_major, "%d", &major) && sscanf(vtk_minor, "%d", &minor) && + major == 4 && minor <= 4) + { + includeSourceDir = true; + } + } + std::string flagVar = "CMAKE_INCLUDE_FLAG_"; + flagVar += lang; + const char* includeFlag = m_Makefile->GetDefinition(flagVar.c_str()); + flagVar = "CMAKE_INCLUDE_FLAG_SEP_"; + flagVar += lang; + const char* sep = m_Makefile->GetDefinition(flagVar.c_str()); + + bool repeatFlag = true; // should the include flag be repeated like ie. -IA -IB + if(!sep) + { + sep = " "; + } + else + { + // if there is a separator then the flag is not repeated but is only given once + // i.e. -classpath a:b:c + repeatFlag = false; + } + bool flagUsed = false; + if(includeSourceDir) + { + includeFlags << includeFlag + << this->ConvertToOutputForExisting(m_Makefile->GetStartDirectory()) + << sep; + flagUsed = true; + } + + implicitIncludes["/usr/include"] = "/usr/include"; + if(m_Makefile->GetDefinition("CMAKE_PLATFORM_IMPLICIT_INCLUDE_DIRECTORIES")) + { + std::string arg = m_Makefile->GetDefinition("CMAKE_PLATFORM_IMPLICIT_INCLUDE_DIRECTORIES"); + std::vector<std::string> implicitIncludeVec; + cmSystemTools::ExpandListArgument(arg, implicitIncludeVec); + for(unsigned int k =0; k < implicitIncludeVec.size(); k++) + { + implicitIncludes[implicitIncludeVec[k]] = implicitIncludeVec[k]; + } + } + + for(i = includes.begin(); i != includes.end(); ++i) + { + std::string include = *i; + // Don't output a -I for the standard include path "/usr/include". + // This can cause problems with certain standard library + // implementations because the wrong headers may be found first. + if(implicitIncludes.find(include) == implicitIncludes.end()) + { + if(!flagUsed || repeatFlag) + { + includeFlags << includeFlag; + flagUsed = true; + } + includeFlags << this->ConvertToOutputForExisting(i->c_str()) << sep; + } + } + std::string flags = includeFlags.str(); + // remove trailing separators + if((sep[0] != ' ') && flags[flags.size()-1] == sep[0]) + { + flags[flags.size()-1] = ' '; + } + flags += m_Makefile->GetDefineFlags(); + m_LanguageToIncludeFlags[lang] = flags; + return m_LanguageToIncludeFlags[lang].c_str(); + +} + + +void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, + std::string& flags, + std::string& linkFlags, + cmTarget& target) +{ + std::string buildType = m_Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + buildType = cmSystemTools::UpperCase(buildType); + const char* libraryLinkVariable = "CMAKE_SHARED_LINKER_FLAGS"; // default to shared library + + switch(target.GetType()) + { + case cmTarget::STATIC_LIBRARY: + { + const char* targetLinkFlags = target.GetProperty("STATIC_LIBRARY_FLAGS"); + if(targetLinkFlags) + { + linkFlags += targetLinkFlags; + linkFlags += " "; + } + } + break; + case cmTarget::MODULE_LIBRARY: + libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS"; + case cmTarget::SHARED_LIBRARY: + { + linkFlags = m_Makefile->GetSafeDefinition(libraryLinkVariable); + linkFlags += " "; + if(buildType.size()) + { + std::string build = libraryLinkVariable; + build += "_"; + build += buildType; + linkFlags += m_Makefile->GetSafeDefinition(build.c_str()); + linkFlags += " "; + } + if(m_Makefile->IsOn("WIN32") && !(m_Makefile->IsOn("CYGWIN") || m_Makefile->IsOn("MINGW"))) + { + const std::vector<cmSourceFile*>& sources = target.GetSourceFiles(); + for(std::vector<cmSourceFile*>::const_iterator i = sources.begin(); + i != sources.end(); ++i) + { + if((*i)->GetSourceExtension() == "def") + { + linkFlags += m_Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); + linkFlags += this->ConvertToRelativeOutputPath((*i)->GetFullPath().c_str()); + linkFlags += " "; + } + } + } + const char* targetLinkFlags = target.GetProperty("LINK_FLAGS"); + if(targetLinkFlags) + { + linkFlags += targetLinkFlags; + linkFlags += " "; + } + cmOStringStream linklibsStr; + this->OutputLinkLibraries(linklibsStr, target.GetName(), target); + linkLibs = linklibsStr.str(); + } + break; + case cmTarget::EXECUTABLE: + { + linkFlags += m_Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS"); + linkFlags += " "; + if(buildType.size()) + { + std::string build = "CMAKE_EXE_LINKER_FLAGS_"; + build += buildType; + linkFlags += m_Makefile->GetSafeDefinition(build.c_str()); + linkFlags += " "; + } + const char* linkLanguage = target.GetLinkerLanguage(this->GetGlobalGenerator()); + std::string langVar = "CMAKE_"; + langVar += linkLanguage; + std::string flagsVar = langVar + "_FLAGS"; + std::string sharedFlagsVar = "CMAKE_SHARED_LIBRARY_"; + sharedFlagsVar += langVar; + sharedFlagsVar += "_FLAGS"; + flags += m_Makefile->GetSafeDefinition(flagsVar.c_str()); + flags += " "; + flags += m_Makefile->GetSafeDefinition(sharedFlagsVar.c_str()); + flags += " "; + cmOStringStream linklibs; + this->OutputLinkLibraries(linklibs, 0, target); + linkLibs = linklibs.str(); + if(cmSystemTools::IsOn(m_Makefile->GetDefinition("BUILD_SHARED_LIBS"))) + { + std::string sFlagVar = std::string("CMAKE_SHARED_BUILD_") + linkLanguage + + std::string("_FLAGS"); + linkFlags += m_Makefile->GetSafeDefinition(sFlagVar.c_str()); + linkFlags += " "; + } + if ( target.GetPropertyAsBool("WIN32_EXECUTABLE") ) + { + linkFlags += m_Makefile->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE"); + linkFlags += " "; + } + else + { + linkFlags += m_Makefile->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE"); + linkFlags += " "; + } + const char* targetLinkFlags = target.GetProperty("LINK_FLAGS"); + if(targetLinkFlags) + { + linkFlags += targetLinkFlags; + linkFlags += " "; + } + } + break; + } +} + + +/** + * Output the linking rules on a command line. For executables, + * targetLibrary should be a NULL pointer. For libraries, it should point + * to the name of the library. This will not link a library against itself. + */ +void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout, + const char* targetLibrary, + const cmTarget &tgt) +{ + // Try to emit each search path once + std::set<cmStdString> emitted; + + // Embed runtime search paths if possible and if required. + bool outputRuntime = true; + std::string runtimeFlag; + std::string runtimeSep; + std::vector<std::string> runtimeDirs; + + std::string buildType = m_Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + buildType = cmSystemTools::UpperCase(buildType); + + const char* linkLanguage = tgt.GetLinkerLanguage(this->GetGlobalGenerator()); + std::string runTimeFlagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; + runTimeFlagVar += linkLanguage; + runTimeFlagVar += "_FLAG"; + std::string runTimeFlagSepVar = runTimeFlagVar + "_SEP"; + runtimeFlag = m_Makefile->GetSafeDefinition(runTimeFlagVar.c_str()); + runtimeSep = m_Makefile->GetSafeDefinition(runTimeFlagSepVar.c_str()); + + // concatenate all paths or no? + bool runtimeConcatenate = ( runtimeSep!="" ); + if(runtimeFlag == "" || m_Makefile->IsOn("CMAKE_SKIP_RPATH") ) + { + outputRuntime = false; + } + + // Some search paths should never be emitted + emitted.insert(""); + emitted.insert("/usr/lib"); + std::string libPathFlag = m_Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG"); + std::string libLinkFlag = m_Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG"); + // collect all the flags needed for linking libraries + std::string linkLibs; + + // Flags to link an executable to shared libraries. + std::string linkFlagsVar = "CMAKE_SHARED_LIBRARY_LINK_"; + linkFlagsVar += linkLanguage; + linkFlagsVar += "_FLAGS"; + if( tgt.GetType() == cmTarget::EXECUTABLE ) + { + linkLibs = m_Makefile->GetSafeDefinition(linkFlagsVar.c_str()); + linkLibs += " "; + } + + const std::vector<std::string>& libdirs = tgt.GetLinkDirectories(); + for(std::vector<std::string>::const_iterator libDir = libdirs.begin(); + libDir != libdirs.end(); ++libDir) + { + std::string libpath = this->ConvertToOutputForExisting(libDir->c_str()); + if(emitted.insert(libpath).second) + { + std::string fullLibPath; + if(!m_WindowsShell && m_UseRelativePaths) + { + fullLibPath = "\"`cd "; + } + fullLibPath += libpath; + if(!m_WindowsShell && m_UseRelativePaths) + { + fullLibPath += ";pwd`\""; + } + std::string::size_type pos = libDir->find(libPathFlag.c_str()); + if((pos == std::string::npos || pos > 0) + && libDir->find("${") == std::string::npos) + { + linkLibs += libPathFlag; + if(outputRuntime) + { + runtimeDirs.push_back( fullLibPath ); + } + } + linkLibs += fullLibPath; + linkLibs += " "; + } + } + + std::string linkSuffix = m_Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX"); + std::string regexp = ".*\\"; + regexp += linkSuffix; + regexp += "$"; + cmsys::RegularExpression hasSuffix(regexp.c_str()); + std::string librariesLinked; + const cmTarget::LinkLibraries& libs = tgt.GetLinkLibraries(); + for(cmTarget::LinkLibraries::const_iterator lib = libs.begin(); + lib != libs.end(); ++lib) + { + // Don't link the library against itself! + if(targetLibrary && (lib->first == targetLibrary)) continue; + // use the correct lib for the current configuration + if (lib->second == cmTarget::DEBUG && buildType != "DEBUG") + { + continue; + } + if (lib->second == cmTarget::OPTIMIZED && buildType == "DEBUG") + { + continue; + } + // skip zero size library entries, this may happen + // if a variable expands to nothing. + if (lib->first.size() == 0) continue; + // if it is a full path break it into -L and -l + cmsys::RegularExpression reg("^([ \t]*\\-[lWRB])|([ \t]*\\-framework)|(\\${)|([ \t]*\\-pthread)|([ \t]*`)"); + if(lib->first.find('/') != std::string::npos + && !reg.find(lib->first)) + { + std::string dir, file; + cmSystemTools::SplitProgramPath(lib->first.c_str(), + dir, file); + std::string libpath = this->ConvertToOutputForExisting(dir.c_str()); + if(emitted.insert(libpath).second) + { + linkLibs += libPathFlag; + linkLibs += libpath; + linkLibs += " "; + if(outputRuntime) + { + runtimeDirs.push_back( libpath ); + } + } + cmsys::RegularExpression libname("^lib([^/]*)(\\.so|\\.lib|\\.dll|\\.sl|\\.a|\\.dylib).*"); + cmsys::RegularExpression libname_noprefix("([^/]*)(\\.so|\\.lib|\\.dll|\\.sl|\\.a|\\.dylib).*"); + if(libname.find(file)) + { + // Library had "lib" prefix. + librariesLinked += libLinkFlag; + file = libname.match(1); + // if ignore libprefix is on, + // then add the lib prefix back into the name + if(m_IgnoreLibPrefix) + { + file = "lib" + file; + } + librariesLinked += file; + if(linkSuffix.size() && !hasSuffix.find(file)) + { + librariesLinked += linkSuffix; + } + librariesLinked += " "; + } + else if(libname_noprefix.find(file)) + { + // Library had no "lib" prefix. + librariesLinked += libLinkFlag; + file = libname_noprefix.match(1); + librariesLinked += file; + if(linkSuffix.size() && !hasSuffix.find(file)) + { + librariesLinked += linkSuffix; + } + librariesLinked += " "; + } + else + { + // Error parsing the library name. Just use the full path. + // The linker will give an error if it is invalid. + librariesLinked += lib->first; + librariesLinked += " "; + } + } + // not a full path, so add -l name + else + { + if(!reg.find(lib->first)) + { + librariesLinked += libLinkFlag; + } + librariesLinked += lib->first; + if(linkSuffix.size() && !hasSuffix.find(lib->first)) + { + librariesLinked += linkSuffix; + } + librariesLinked += " "; + } + } + + linkLibs += librariesLinked; + + fout << linkLibs; + + if(outputRuntime && runtimeDirs.size()>0) + { + // For the runtime search directories, do a "-Wl,-rpath,a:b:c" or + // a "-R a -R b -R c" type link line + fout << runtimeFlag; + std::vector<std::string>::iterator itr = runtimeDirs.begin(); + fout << *itr; + ++itr; + for( ; itr != runtimeDirs.end(); ++itr ) + { + if(runtimeConcatenate) + { + fout << runtimeSep << *itr; + } + else + { + fout << " " << runtimeFlag << *itr; + } + } + fout << " "; + } + if(m_Makefile->GetDefinition("CMAKE_STANDARD_LIBRARIES")) + { + fout << m_Makefile->GetDefinition("CMAKE_STANDARD_LIBRARIES") << " "; + } +} |