/*========================================================================= Program: CMake - Cross-Platform Makefile Generator Module: $RCSfile$ Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "cmGlobalGenerator.h" #include "cmLocalUnixMakefileGenerator.h" #include "cmMakefile.h" #include "cmSystemTools.h" #include "cmSourceFile.h" #include "cmMakeDepend.h" #include "cmCacheManager.h" #include "cmGeneratedFileStream.h" #include cmLocalUnixMakefileGenerator::cmLocalUnixMakefileGenerator() { m_WindowsShell = false; m_IncludeDirective = "include"; m_MakefileVariableSize = 0; m_IgnoreLibPrefix = false; m_PassMakeflags = false; } cmLocalUnixMakefileGenerator::~cmLocalUnixMakefileGenerator() { } void cmLocalUnixMakefileGenerator::Generate(bool fromTheTop) { // suppoirt override in output directories if (m_Makefile->GetDefinition("LIBRARY_OUTPUT_PATH")) { m_LibraryOutputPath = m_Makefile->GetDefinition("LIBRARY_OUTPUT_PATH"); if(m_LibraryOutputPath.size()) { if(m_LibraryOutputPath[m_LibraryOutputPath.size() -1] != '/') { m_LibraryOutputPath += "/"; } if(!cmSystemTools::MakeDirectory(m_LibraryOutputPath.c_str())) { cmSystemTools::Error("Error failed create " "LIBRARY_OUTPUT_PATH directory:", m_LibraryOutputPath.c_str()); } m_Makefile->AddLinkDirectory(m_LibraryOutputPath.c_str()); } } if (m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH")) { m_ExecutableOutputPath = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"); if(m_ExecutableOutputPath.size()) { if(m_ExecutableOutputPath[m_ExecutableOutputPath.size() -1] != '/') { m_ExecutableOutputPath += "/"; } if(!cmSystemTools::MakeDirectory(m_ExecutableOutputPath.c_str())) { cmSystemTools::Error("Error failed to create " "EXECUTABLE_OUTPUT_PATH directory:", m_ExecutableOutputPath.c_str()); } m_Makefile->AddLinkDirectory(m_ExecutableOutputPath.c_str()); } } if (!fromTheTop) { // Generate depends cmMakeDepend md; md.SetMakefile(m_Makefile); md.GenerateMakefileDependencies(); this->ProcessDepends(md); } // output the makefile fragment std::string dest = m_Makefile->GetStartOutputDirectory(); dest += "/Makefile"; this->OutputMakefile(dest.c_str(), !fromTheTop); } void cmLocalUnixMakefileGenerator::AddDependenciesToSourceFile(cmDependInformation const *info, cmSourceFile *i, std::set *visited) { // add info to the visited set visited->insert(info); // add this dependency and the recurse // now recurse with info's dependencies for(cmDependInformation::DependencySet::const_iterator d = info->m_DependencySet.begin(); d != info->m_DependencySet.end(); ++d) { if (visited->find(*d) == visited->end()) { if((*d)->m_FullPath != "") { i->GetDepends().push_back((*d)->m_FullPath.c_str()); } this->AddDependenciesToSourceFile(*d,i,visited); } } } void cmLocalUnixMakefileGenerator::ProcessDepends(const cmMakeDepend &md) { // Now create cmDependInformation objects for files in the directory cmTargets &tgts = m_Makefile->GetTargets(); for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) { std::vector &classes = l->second.GetSourceFiles(); for(std::vector::iterator i = classes.begin(); i != classes.end(); ++i) { if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY")) { // get the depends const cmDependInformation *info = md.GetDependInformationForSourceFile(*(*i)); // Delete any hints from the source file's dependencies. (*i)->GetDepends().erase((*i)->GetDepends().begin(), (*i)->GetDepends().end()); // Now add the real dependencies for the file. if (info) { // create visited set std::set visited; this->AddDependenciesToSourceFile(info,*i, &visited); } } } } } // This is where CMakeTargets.make is generated void cmLocalUnixMakefileGenerator::OutputMakefile(const char* file, bool withDepends) { // Create sub directories fro aux source directories std::vector& auxSourceDirs = m_Makefile->GetAuxSourceDirectories(); if( auxSourceDirs.size() ) { // For the case when this is running as a remote build // on unix, make the directory for(std::vector::iterator i = auxSourceDirs.begin(); i != auxSourceDirs.end(); ++i) { if(i->c_str()[0] != '/') { std::string dir = m_Makefile->GetCurrentOutputDirectory(); if(dir.size() && dir[dir.size()-1] != '/') { dir += "/"; } dir += *i; cmSystemTools::MakeDirectory(dir.c_str()); } else { cmSystemTools::MakeDirectory(i->c_str()); } } } // Create a stream that writes to a temporary file // then does a copy at the end. This is to allow users // to hit control-c during the make of the makefile cmGeneratedFileStream tempFile(file); tempFile.SetAlwaysCopy(true); std::ostream& fout = tempFile.GetStream(); if(!fout) { cmSystemTools::Error("Error can not open for write: ", file); return; } fout << "# CMAKE generated Makefile, DO NOT EDIT!\n" << "# Generated by \"" << m_GlobalGenerator->GetName() << "\"" << " Generator, CMake Version " << cmMakefile::GetMajorVersion() << "." << cmMakefile::GetMinorVersion() << "\n" << "# Generated from the following files:\n# " << m_Makefile->GetHomeOutputDirectory() << "/CMakeCache.txt\n"; std::vector lfiles = m_Makefile->GetListFiles(); // sort the array std::sort(lfiles.begin(), lfiles.end(), std::less()); // remove duplicates std::vector::iterator new_end = std::unique(lfiles.begin(), lfiles.end()); lfiles.erase(new_end, lfiles.end()); for(std::vector::const_iterator i = lfiles.begin(); i != lfiles.end(); ++i) { fout << "# " << i->c_str() << "\n"; } fout << "\n\n"; fout << "# disable some common implicit rules to speed things up\n"; fout << ".SUFFIXES:\n"; fout << ".SUFFIXES:.hpuxmakemusthaverule\n"; // create a make variable with all of the sources for this Makefile // for depend purposes. fout << "CMAKE_MAKEFILE_SOURCES = "; for(std::vector::const_iterator i = lfiles.begin(); i != lfiles.end(); ++i) { fout << " " << this->ConvertToRelativeOutputPath(i->c_str()); } // Add the cache to the list std::string cacheFile = m_Makefile->GetHomeOutputDirectory(); cacheFile += "/CMakeCache.txt"; fout << " " << this->ConvertToRelativeOutputPath(cacheFile.c_str()); fout << "\n\n\n"; this->OutputMakeVariables(fout); std::string checkCache = m_Makefile->GetHomeOutputDirectory(); checkCache += "/cmake.check_cache"; checkCache = this->ConvertToRelativeOutputPath(checkCache.c_str()); // most unix makes will pass the command line flags to make down // to sub invoked makes via an environment variable. However, some // makes do not support that, so you have to pass the flags explicitly const char* allRule = "$(MAKE) $(MAKESILENT) all"; if(m_PassMakeflags) { allRule = "$(MAKE) $(MAKESILENT) -$(MAKEFLAGS) all"; } // Set up the default target as the VERY first target, so that make with no arguments will run it this-> OutputMakeRule(fout, "Default target executed when no arguments are given to make, first make sure cmake.depends exists, cmake.check_depends is up-to-date, check the sources, then build the all target", "default_target", checkCache.c_str(), "$(MAKE) $(MAKESILENT) cmake.depends", "$(MAKE) $(MAKESILENT) cmake.check_depends", "$(MAKE) $(MAKESILENT) -f cmake.check_depends", allRule); // Generation of SILENT target must be after default_target. if(!m_Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")) { fout << "# Suppresses display of executed commands\n"; fout << "$(VERBOSE).SILENT:\n\n"; } this->OutputTargetRules(fout); this->OutputDependLibs(fout); this->OutputTargets(fout); this->OutputSubDirectoryRules(fout); std::string dependName = m_Makefile->GetStartOutputDirectory(); dependName += "/cmake.depends"; if(withDepends) { std::ofstream dependout(dependName.c_str()); if(!dependout) { cmSystemTools::Error("Error can not open for write: ", dependName.c_str()); return; } dependout << "# .o dependencies in this directory." << std::endl; std::string checkDepend = m_Makefile->GetStartOutputDirectory(); checkDepend += "/cmake.check_depends"; std::ofstream checkdependout(checkDepend.c_str()); if(!checkdependout) { cmSystemTools::Error("Error can not open for write: ", checkDepend.c_str()); return; } checkdependout << "# This file is used as a tag file, that all sources depend on. If a source changes, then the rule to rebuild this file will cause cmake.depends to be rebuilt." << std::endl; // if there were any depends output, then output the check depends // information inot checkdependout if(this->OutputObjectDepends(dependout)) { this->OutputCheckDepends(checkdependout); } else { checkdependout << "all:\n\t@echo cmake.depends is up-to-date\n"; } } this->OutputCustomRules(fout); this->OutputMakeRules(fout); this->OutputInstallRules(fout); // only add the depend include if the depend file exists if(cmSystemTools::FileExists(dependName.c_str())) { fout << m_IncludeDirective << " cmake.depends\n"; } } std::string cmLocalUnixMakefileGenerator::GetOutputExtension(const char* s) { if(m_Makefile->IsOn("WIN32") && !(m_Makefile->IsOn("CYGWIN") || m_Makefile->IsOn("MINGW"))) { std::string sourceExtension = s; if(sourceExtension == "def") { return ""; } if(sourceExtension == "ico" || sourceExtension == "rc2") { return ""; } if(sourceExtension == "rc") { return ".res"; } return ".obj"; } else { return ".o"; } } std::string cmLocalUnixMakefileGenerator::GetBaseTargetName(const char* n, const cmTarget& t) { const char* targetPrefix = t.GetProperty("PREFIX"); const char* prefixVar = 0; switch(t.GetType()) { case cmTarget::STATIC_LIBRARY: prefixVar = "CMAKE_STATIC_LIBRARY_PREFIX"; break; case cmTarget::SHARED_LIBRARY: prefixVar = "CMAKE_SHARED_LIBRARY_PREFIX"; break; case cmTarget::MODULE_LIBRARY: prefixVar = "CMAKE_SHARED_MODULE_PREFIX"; break; case cmTarget::EXECUTABLE: case cmTarget::UTILITY: case cmTarget::INSTALL_FILES: case cmTarget::INSTALL_PROGRAMS: break; } // if there is no prefix on the target use the cmake definition if(!targetPrefix && prefixVar) { targetPrefix = this->GetSafeDefinition(prefixVar); } std::string name = targetPrefix?targetPrefix:""; name += n; return name; } std::string cmLocalUnixMakefileGenerator::GetFullTargetName(const char* n, const cmTarget& t) { const char* targetSuffix = t.GetProperty("SUFFIX"); const char* suffixVar = 0; switch(t.GetType()) { case cmTarget::STATIC_LIBRARY: suffixVar = "CMAKE_STATIC_LIBRARY_SUFFIX"; break; case cmTarget::SHARED_LIBRARY: suffixVar = "CMAKE_SHARED_LIBRARY_SUFFIX"; break; case cmTarget::MODULE_LIBRARY: suffixVar = "CMAKE_SHARED_MODULE_SUFFIX"; break; case cmTarget::EXECUTABLE: targetSuffix = cmSystemTools::GetExecutableExtension(); case cmTarget::UTILITY: case cmTarget::INSTALL_FILES: case cmTarget::INSTALL_PROGRAMS: break; } // if there is no suffix on the target use the cmake definition if(!targetSuffix && suffixVar) { targetSuffix = this->GetSafeDefinition(suffixVar); } std::string name = this->GetBaseTargetName(n, t); name += targetSuffix?targetSuffix:""; return name; } // Output the rules for any targets void cmLocalUnixMakefileGenerator::OutputEcho(std::ostream& fout, const char *msg) { std::string echostring = msg; // for unix we want to quote the output of echo // for nmake and borland, the echo should not be quoted if(strcmp(m_GlobalGenerator->GetName(), "Unix Makefiles") == 0) { cmSystemTools::ReplaceString(echostring, "\\\n", " "); cmSystemTools::ReplaceString(echostring, " \t", " "); cmSystemTools::ReplaceString(echostring, "\n\t", "\"\n\t@echo \""); fout << "\t@echo \"" << echostring.c_str() << "\"\n"; } else { cmSystemTools::ReplaceString(echostring, "\n\t", "\n\t@echo "); fout << "\t@echo " << echostring.c_str() << "\n"; } } // Output the rules for any targets void cmLocalUnixMakefileGenerator::OutputTargetRules(std::ostream& fout) { const cmTargets &tgts = m_Makefile->GetTargets(); // add the help target fout << "help:\n"; this->OutputEcho(fout,"The following are some of the valid targets for this Makefile:"); this->OutputEcho(fout,"... all (the default if no target is provided)"); this->OutputEcho(fout,"... clean"); this->OutputEcho(fout,"... depend"); this->OutputEcho(fout,"... rebuild_cache"); // libraries std::string path; for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { if((l->second.GetType() == cmTarget::STATIC_LIBRARY) || (l->second.GetType() == cmTarget::SHARED_LIBRARY) || (l->second.GetType() == cmTarget::MODULE_LIBRARY)) { std::string path2 = m_LibraryOutputPath; path2 += this->GetFullTargetName(l->first.c_str(), l->second); path = "... "; path += this->ConvertToRelativeOutputPath(path2.c_str()); this->OutputEcho(fout,path.c_str()); } } // executables for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { if ( l->second.GetType() == cmTarget::EXECUTABLE ) { path = "... "; path += l->first + cmSystemTools::GetExecutableExtension(); this->OutputEcho(fout,path.c_str()); } } // list utilities last for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { if (l->second.GetType() == cmTarget::UTILITY) { path = "... "; path += l->first; this->OutputEcho(fout,path.c_str()); } } fout << "\n\n"; // for each target add to the list of targets fout << "TARGETS = "; // list libraries first for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { if (l->second.IsInAll()) { if((l->second.GetType() == cmTarget::STATIC_LIBRARY) || (l->second.GetType() == cmTarget::SHARED_LIBRARY) || (l->second.GetType() == cmTarget::MODULE_LIBRARY)) { path = m_LibraryOutputPath; path += this->GetFullTargetName(l->first.c_str(), l->second); fout << " \\\n" << this->ConvertToMakeTarget(this->ConvertToRelativeOutputPath(path.c_str()).c_str()); } } } // executables for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { if (l->second.GetType() == cmTarget::EXECUTABLE && l->second.IsInAll()) { path = m_ExecutableOutputPath; path += this->GetFullTargetName(l->first.c_str(), l->second); fout << " \\\n" << this->ConvertToMakeTarget(this->ConvertToRelativeOutputPath(path.c_str()).c_str()); } } // list utilities last for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { if (l->second.GetType() == cmTarget::UTILITY && l->second.IsInAll()) { fout << " \\\n" << l->first.c_str(); } } fout << "\n\n"; // get the classes from the source lists then add them to the groups for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { std::vector classes = l->second.GetSourceFiles(); if (classes.begin() != classes.end()) { fout << this->CreateMakeVariable(l->first.c_str(), "_SRC_OBJS") << " = "; for(std::vector::iterator i = classes.begin(); i != classes.end(); i++) { if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY") && !(*i)->GetCustomCommand()) { std::string outExt( this->GetOutputExtension((*i)->GetSourceExtension().c_str())); if(outExt.size()) { fout << "\\\n" << this->ConvertToMakeTarget(this->ConvertToRelativeOutputPath((*i)->GetSourceName().c_str()).c_str()) << outExt.c_str() << " "; } } } fout << "\n\n"; fout << this->CreateMakeVariable(l->first.c_str(), "_SRC_OBJS_QUOTED") << " = "; for(std::vector::iterator i = classes.begin(); i != classes.end(); i++) { if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY") && !(*i)->GetCustomCommand()) { std::string outExt(this->GetOutputExtension((*i)->GetSourceExtension().c_str())); if(outExt.size()) { fout << "\\\n\"" << this->ConvertToMakeTarget(ConvertToRelativeOutputPath((*i)->GetSourceName().c_str()).c_str()) << outExt.c_str() << "\" "; } } } fout << "\n\n"; } } // This list contains extra files created for a target. It includes // the extra names associated with a versioned shared library. fout << "TARGET_EXTRAS = "; for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { if (l->second.IsInAll()) { if(l->second.GetType() == cmTarget::SHARED_LIBRARY || l->second.GetType() == cmTarget::MODULE_LIBRARY) { std::string targetName; std::string targetNameSO; std::string targetNameReal; std::string targetNameBase; this->GetLibraryNames(l->first.c_str(), l->second, targetName, targetNameSO, targetNameReal, targetNameBase); if(targetNameSO != targetName) { path = m_LibraryOutputPath; path += targetNameSO; fout << " \\\n" << this->ConvertToRelativeOutputPath(path.c_str()); } if(targetNameReal != targetName && targetNameReal != targetNameSO) { path = m_LibraryOutputPath; path += targetNameReal; fout << " \\\n" << this->ConvertToRelativeOutputPath(path.c_str()); } } } } fout << "\n\n"; fout << "CLEAN_OBJECT_FILES = "; for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { std::vector classes = l->second.GetSourceFiles(); if (classes.begin() != classes.end()) { fout << "$(" << this->CreateMakeVariable(l->first.c_str(), "_SRC_OBJS") << ") "; } } fout << "\n\n"; const char * qt_files = m_Makefile->GetDefinition("GENERATED_QT_FILES"); if (qt_files != NULL && strlen(m_Makefile->GetDefinition("GENERATED_QT_FILES"))>0) { fout << "GENERATED_QT_FILES = "; fout << qt_files; fout << "\n\n"; } } /** * 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 cmLocalUnixMakefileGenerator::OutputLinkLibraries(std::ostream& fout, const char* targetLibrary, const cmTarget &tgt) { // Try to emit each search path once std::set emitted; // Embed runtime search paths if possible and if required. bool outputRuntime = true; std::string runtimeFlag; std::string runtimeSep; std::vector runtimeDirs; std::string buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); buildType = cmSystemTools::UpperCase(buildType); bool cxx = tgt.HasCxx(); if(!cxx ) { // if linking a c executable use the C runtime flag as cc // may not be the same program that creates shared libaries // and may have different flags runtimeFlag = this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_RUNTIME_FLAG"); runtimeSep = this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_RUNTIME_FLAG_SEP"); } else { runtimeFlag = this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG"); runtimeSep = this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP"); } // 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->GetDefinition("CMAKE_LIBRARY_PATH_FLAG"); std::string libLinkFlag = this->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG"); // collect all the flags needed for linking libraries std::string linkLibs; // Flags to link an executable to shared libraries. if( tgt.GetType() == cmTarget::EXECUTABLE ) { if(cxx) { linkLibs = this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS"); } else { linkLibs = this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_LINK_FLAGS"); } linkLibs += " "; } const std::vector& libdirs = tgt.GetLinkDirectories(); for(std::vector::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) { fullLibPath = "\"`cd "; } fullLibPath += libpath; if(!m_WindowsShell) { 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 = this->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]*\\-[lWR])|([ \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) { std::cout << "m_IgnoreLibPrefix\n"; 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::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") << " "; } } std::string cmLocalUnixMakefileGenerator::CreatePreBuildRules( const cmTarget &target, const char* /* targetName */) { std::string customRuleCode = ""; bool initNext = false; for (std::vector::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 = this->ConvertToRelativeOutputPath(cc.GetCommand().c_str()); customRuleCode += command + " " + cc.GetArguments(); } return customRuleCode; } std::string cmLocalUnixMakefileGenerator::CreatePreLinkRules( const cmTarget &target, const char* /* targetName */) { std::string customRuleCode = ""; bool initNext = false; for (std::vector::const_iterator cr = target.GetPreLinkCommands().begin(); cr != target.GetPreLinkCommands().end(); ++cr) { cmCustomCommand cc(*cr); cc.ExpandVariables(*m_Makefile); if(initNext) { customRuleCode += "\n\t"; } else { initNext = true; } std::string command = this->ConvertToRelativeOutputPath(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::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 = this->ConvertToRelativeOutputPath(cc.GetCommand().c_str()); customRuleCode += command + " " + cc.GetArguments(); } return customRuleCode; } struct RuleVariables { const char* replace; const char* lookup; }; static RuleVariables ruleReplaceVars[] = { {"", "CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS"}, {"", "CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS"}, {"", "CMAKE_SHARED_MODULE_C_FLAGS"}, {"", "CMAKE_SHARED_MODULE_CXX_FLAGS"}, {"", "CMAKE_SHARED_LIBRARY_C_FLAGS"}, {"", "CMAKE_SHARED_LIBRARY_CXX_FLAGS"}, {"", "CMAKE_CXX_LINK_FLAGS"}, {"", "CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS"}, {"", "CMAKE_SHARED_MODULE_CREATE_C_FLAGS"}, {"", "CMAKE_SHARED_LIBRARY_SONAME_C_FLAG"}, {"", "CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG"}, {"", "CMAKE_C_LINK_FLAGS"}, {"", "CMAKE_AR"}, {"", "CMAKE_RANLIB"}, {0, 0} }; void cmLocalUnixMakefileGenerator::ExpandRuleVariables(std::string& s, 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::string cxxcompiler = this->ConvertToOutputForExisting( this->GetSafeDefinition("CMAKE_CXX_COMPILER")); std::string ccompiler = this->ConvertToOutputForExisting( this->GetSafeDefinition("CMAKE_C_COMPILER")); cmSystemTools::ReplaceString(s, "", cxxcompiler.c_str()); cmSystemTools::ReplaceString(s, "", ccompiler.c_str()); if(linkFlags) { cmSystemTools::ReplaceString(s, "", linkFlags); } if(flags) { cmSystemTools::ReplaceString(s, "", flags); } if(source) { cmSystemTools::ReplaceString(s, "", source); } if(object) { cmSystemTools::ReplaceString(s, "", object); } if(objects) { cmSystemTools::ReplaceString(s, "", objects); } if(objectsquoted) { cmSystemTools::ReplaceString(s, "", objectsquoted); } if(target) { std::string targetQuoted = target; if(targetQuoted.size() && targetQuoted[0] != '\"') { targetQuoted = '\"'; targetQuoted += target; targetQuoted += '\"'; } cmSystemTools::ReplaceString(s, "", targetQuoted.c_str()); cmSystemTools::ReplaceString(s, "", target); } if(targetBase) { // special case for quoted paths with spaces // if you see .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, ".lib", baseLib.c_str()); cmSystemTools::ReplaceString(s, ".dll", baseDll.c_str()); } cmSystemTools::ReplaceString(s, "", targetBase); } if(targetSOName) { if(m_Makefile->GetDefinition("CMAKE_SHARED_LIBRARY_SONAME_C_FLAG")) { cmSystemTools::ReplaceString(s, "", targetSOName); } else { cmSystemTools::ReplaceString(s, "", ""); } } if(linkLibs) { cmSystemTools::ReplaceString(s, "", linkLibs); } RuleVariables* rv = ruleReplaceVars; while(rv->replace) { cmSystemTools::ReplaceString(s, rv->replace, this->GetSafeDefinition(rv->lookup)); rv++; } } void cmLocalUnixMakefileGenerator::OutputLibraryRule(std::ostream& fout, const char* name, const cmTarget &t, const char* createVariable, const char* comment, const char* linkFlags ) { std::string targetName; std::string targetNameSO; std::string targetNameReal; std::string targetNameBase; this->GetLibraryNames(name, t, targetName, targetNameSO, targetNameReal, targetNameBase); std::string outpath; std::string outdir = this->ConvertToRelativeOutputPath(m_LibraryOutputPath.c_str()); if(!m_WindowsShell && outdir.size()) { outpath = "\"`cd "; } outpath += outdir; if(!m_WindowsShell && outdir.size()) { outpath += ";pwd`\"/"; } if(outdir.size() == 0 && !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; // get the objects that are used to link this library std::string objs = "$(" + this->CreateMakeVariable(name, "_SRC_OBJS") + ") "; std::string objsQuoted = "$(" + this->CreateMakeVariable(name, "_SRC_OBJS_QUOTED") + ") "; // create a variable with the objects that this library depends on std::string depend = objs + " $(" + this->CreateMakeVariable(name, "_DEPEND_LIBS") + ")"; std::vector commands; std::string cmakecommand = this->ConvertToOutputForExisting( m_Makefile->GetDefinition("CMAKE_COMMAND")); // Remove any existing files for this library. std::string remove = cmakecommand; remove += " -E remove -f "; remove += targetFullPathReal; if(targetFullPathSO != targetFullPathReal) { remove += " "; remove += targetFullPathSO; } if(targetFullPath != targetFullPathSO && targetFullPath != targetFullPathReal) { remove += " "; remove += targetFullPath; } commands.push_back(remove); // 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); } // collect up the build rules std::vector rules; rules.push_back(m_Makefile->GetDefinition(createVariable)); // expand multi-command semi-colon separated lists // of commands into separate commands cmSystemTools::ExpandList(rules, commands); // Create necessary symlinks for library. if(targetFullPath != targetFullPathReal) { std::string symlink = cmakecommand; symlink += " -E cmake_symlink_library "; symlink += targetFullPathReal; symlink += " "; symlink += targetFullPathSO; symlink += " "; symlink += targetFullPath; commands.push_back(symlink); } // collect custom commands for this target and add them to the list customCommands = this->CreatePostBuildRules(t, name); if(customCommands.size() > 0) { commands.push_back(customCommands); } // collect up the link libraries cmOStringStream linklibs; this->OutputLinkLibraries(linklibs, name, t); for(std::vector::iterator i = commands.begin(); i != commands.end(); ++i) { this->ExpandRuleVariables(*i, objs.c_str(), targetFullPathReal.c_str(), linklibs.str().c_str(), 0, 0, 0, objsQuoted.c_str(), targetFullPathBase.c_str(), targetNameSO.c_str(), linkFlags); } targetFullPath = m_LibraryOutputPath + targetName; this->OutputMakeRule(fout, comment, targetFullPath.c_str(), depend.c_str(), commands); depend = targetFullPath; std::string tgt = this->ConvertToRelativeOutputPath(targetFullPath.c_str()); tgt = this->ConvertToMakeTarget(tgt.c_str()); cmSystemTools::ConvertToUnixSlashes(tgt); if(tgt.find('/', 0) != tgt.npos) { // we need a local target depend = this->ConvertToRelativeOutputPath(depend.c_str()); std::string target = targetName; commands.resize(0); this->OutputMakeRule(fout, comment, target.c_str(), depend.c_str(), commands); } } void cmLocalUnixMakefileGenerator::OutputSharedLibraryRule(std::ostream& fout, const char* name, const cmTarget &t) { const char* createRule; if(t.HasCxx()) { createRule = "CMAKE_CXX_CREATE_SHARED_LIBRARY"; } else { createRule = "CMAKE_C_CREATE_SHARED_LIBRARY"; } std::string buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); buildType = cmSystemTools::UpperCase(buildType); std::string linkFlags = this->GetSafeDefinition("CMAKE_SHARED_LINKER_FLAGS"); linkFlags += " "; if(buildType.size()) { std::string build = "CMAKE_SHARED_LINKER_FLAGS_"; build += buildType; linkFlags += this->GetSafeDefinition(build.c_str()); linkFlags += " "; } if(m_Makefile->IsOn("WIN32") && !(m_Makefile->IsOn("CYGWIN") || m_Makefile->IsOn("MINGW"))) { const std::vector& sources = t.GetSourceFiles(); for(std::vector::const_iterator i = sources.begin(); i != sources.end(); ++i) { if((*i)->GetSourceExtension() == "def") { linkFlags += this->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); linkFlags += this->ConvertToRelativeOutputPath((*i)->GetFullPath().c_str()); linkFlags += " "; } } } const char* targetLinkFlags = t.GetProperty("LINK_FLAGS"); if(targetLinkFlags) { linkFlags += targetLinkFlags; linkFlags += " "; } this->OutputLibraryRule(fout, name, t, createRule, "shared library", linkFlags.c_str()); } void cmLocalUnixMakefileGenerator::OutputModuleLibraryRule(std::ostream& fout, const char* name, const cmTarget &t) { const char* createRule; if(t.HasCxx()) { createRule = "CMAKE_CXX_CREATE_SHARED_MODULE"; } else { createRule = "CMAKE_C_CREATE_SHARED_MODULE"; } std::string buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); buildType = cmSystemTools::UpperCase(buildType); std::string linkFlags = this->GetSafeDefinition("CMAKE_MODULE_LINKER_FLAGS"); linkFlags += " "; if(buildType.size()) { std::string build = "CMAKE_MODULE_LINKER_FLAGS_"; build += buildType; linkFlags += this->GetSafeDefinition(build.c_str()); linkFlags += " "; } const char* targetLinkFlags = t.GetProperty("LINK_FLAGS"); if(targetLinkFlags) { linkFlags += targetLinkFlags; linkFlags += " "; } this->OutputLibraryRule(fout, name, t, createRule, "shared module", linkFlags.c_str()); } void cmLocalUnixMakefileGenerator::OutputStaticLibraryRule(std::ostream& fout, const char* name, const cmTarget &t) { const char* createRule; if(t.HasCxx()) { createRule = "CMAKE_CXX_CREATE_STATIC_LIBRARY"; } else { createRule = "CMAKE_C_CREATE_STATIC_LIBRARY"; } std::string linkFlags; const char* targetLinkFlags = t.GetProperty("LINK_FLAGS"); if(targetLinkFlags) { linkFlags += targetLinkFlags; linkFlags += " "; } this->OutputLibraryRule(fout, name, t, createRule, "static library", linkFlags.c_str()); } void cmLocalUnixMakefileGenerator::OutputExecutableRule(std::ostream& fout, const char* name, const cmTarget &t) { std::string linkFlags; std::string buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); buildType = cmSystemTools::UpperCase(buildType); std::string flags; // Construct the full path to the executable that will be generated. std::string target = m_ExecutableOutputPath; if(target.length() == 0) { target = m_Makefile->GetCurrentOutputDirectory(); if(target.size() && target[target.size()-1] != '/') { target += "/"; } } #ifdef __APPLE__ if ( t.GetPropertyAsBool("MACOSX_BUNDLE") ) { // Make bundle directories target += name; target += ".app/Contents/MacOS/"; } #endif target += name; target += cmSystemTools::GetExecutableExtension(); target = this->ConvertToRelativeOutputPath(target.c_str()); cmSystemTools::ConvertToUnixSlashes(target); bool needsLocalTarget = false; std::string tgt = this->ConvertToMakeTarget(target.c_str()); if(tgt.find('/', 0) != tgt.npos) { needsLocalTarget = true; } target = cmSystemTools::ConvertToOutputPath(target.c_str()); std::string objs = "$(" + this->CreateMakeVariable(name, "_SRC_OBJS") + ") "; std::string depend = "$("; depend += this->CreateMakeVariable(name, "_SRC_OBJS") + ") $(" + this->CreateMakeVariable(name, "_DEPEND_LIBS") + ")"; std::vector rules; linkFlags += this->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS"); linkFlags += " "; if(buildType.size()) { std::string build = "CMAKE_EXE_LINKER_FLAGS_"; build += buildType; linkFlags += this->GetSafeDefinition(build.c_str()); linkFlags += " "; } if(t.HasCxx()) { rules.push_back(m_Makefile->GetDefinition("CMAKE_CXX_LINK_EXECUTABLE")); flags += this->GetSafeDefinition("CMAKE_CXX_FLAGS"); flags += " "; flags += this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_CXX_FLAGS"); flags += " "; } else { rules.push_back(m_Makefile->GetDefinition("CMAKE_C_LINK_EXECUTABLE")); flags += this->GetSafeDefinition("CMAKE_C_FLAGS"); flags += " "; flags += this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_C_FLAGS"); flags += " "; } cmOStringStream linklibs; this->OutputLinkLibraries(linklibs, 0, t); std::string comment = "executable"; std::vector 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); customCommands = this->CreatePostBuildRules(t, name); if(customCommands.size() > 0) { commands.push_back(customCommands.c_str()); } if(cmSystemTools::IsOn(m_Makefile->GetDefinition("BUILD_SHARED_LIBS"))) { linkFlags += this->GetSafeDefinition("CMAKE_SHARED_BUILD_CXX_FLAGS"); linkFlags += " "; } if ( t.GetPropertyAsBool("WIN32_EXECUTABLE") ) { linkFlags += this->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE"); linkFlags += " "; } else { linkFlags += this->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE"); linkFlags += " "; } const char* targetLinkFlags = t.GetProperty("LINK_FLAGS"); if(targetLinkFlags) { linkFlags += targetLinkFlags; linkFlags += " "; } for(std::vector::iterator i = commands.begin(); i != commands.end(); ++i) { this->ExpandRuleVariables(*i, objs.c_str(), target.c_str(), linklibs.str().c_str(), 0, 0, flags.c_str(), 0, 0, 0, linkFlags.c_str()); } this->OutputMakeRule(fout, comment.c_str(), target.c_str(), depend.c_str(), commands); // If there is no executable output path, add a rule with the // relative path to the executable. This is necessary for // try-compile to work in this case. if(needsLocalTarget) { depend = target; target = name; target += cmSystemTools::GetExecutableExtension(); target = this->ConvertToRelativeOutputPath(target.c_str()); commands.resize(0); this->OutputMakeRule(fout, comment.c_str(), target.c_str(), depend.c_str(), commands); } } void cmLocalUnixMakefileGenerator::OutputUtilityRule(std::ostream& fout, const char* name, const cmTarget &t) { 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(); } std::string comment = "Utility"; std::string depends; depends = "$(" + this->CreateMakeVariable(name, "_DEPEND_LIBS") + ")"; std::string replaceVars; const std::vector &ccs = t.GetPostBuildCommands(); for(std::vector::const_iterator i = ccs.begin(); i != ccs.end(); ++i) { const std::vector & dep = i->GetDepends(); for(std::vector::const_iterator d = dep.begin(); d != dep.end(); ++d) { depends += " \\\n"; replaceVars = *d; m_Makefile->ExpandVariablesInString(replaceVars); depends += this->ConvertToMakeTarget(this->ConvertToRelativeOutputPath(replaceVars.c_str()).c_str()); } } this->OutputMakeRule(fout, comment.c_str(), name, depends.c_str(), cc); } void cmLocalUnixMakefileGenerator::OutputTargets(std::ostream& fout) { // for each target const cmTargets &tgts = m_Makefile->GetTargets(); for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { switch(l->second.GetType()) { case cmTarget::STATIC_LIBRARY: this->OutputStaticLibraryRule(fout, l->first.c_str(), l->second); break; case cmTarget::SHARED_LIBRARY: this->OutputSharedLibraryRule(fout, l->first.c_str(), l->second); break; case cmTarget::MODULE_LIBRARY: this->OutputModuleLibraryRule(fout, l->first.c_str(), l->second); break; case cmTarget::EXECUTABLE: this->OutputExecutableRule(fout, l->first.c_str(), l->second); break; case cmTarget::UTILITY: this->OutputUtilityRule(fout, l->first.c_str(), l->second); break; // This is handled by the OutputCustomRules method case cmTarget::INSTALL_FILES: // This is handled by the OutputInstallRules method case cmTarget::INSTALL_PROGRAMS: // This is handled by the OutputInstallRules method break; } } } // For each target that is an executable or shared library, generate // the "_DEPEND_LIBS" variable listing its library dependencies. void cmLocalUnixMakefileGenerator::OutputDependLibs(std::ostream& fout) { // Build a set of libraries that will be linked into any target in // this directory. std::set used; // for each target const cmTargets &tgts = m_Makefile->GetTargets(); for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { // Each dependency should only be emitted once per target. std::set emitted; if ((l->second.GetType() == cmTarget::SHARED_LIBRARY) || (l->second.GetType() == cmTarget::MODULE_LIBRARY) || (l->second.GetType() == cmTarget::STATIC_LIBRARY) || (l->second.GetType() == cmTarget::EXECUTABLE) || (l->second.GetType() == cmTarget::UTILITY)) { fout << this->CreateMakeVariable(l->first.c_str(), "_DEPEND_LIBS") << " = "; // A library should not depend on itself! emitted.insert(l->first); // for static libraries do not depend on other libraries if(l->second.GetType() != cmTarget::STATIC_LIBRARY) { // Now, look at all link libraries specific to this target. const cmTarget::LinkLibraries& tlibs = l->second.GetLinkLibraries(); for(cmTarget::LinkLibraries::const_iterator lib = tlibs.begin(); lib != tlibs.end(); ++lib) { // Record that this library was used. used.insert(lib->first); // Don't emit the same library twice for this target. if(emitted.insert(lib->first).second) { // Output this dependency. this->OutputLibDepend(fout, lib->first.c_str()); } } } // for all targets depend on utilities // Now, look at all utilities specific to this target. const std::set& tutils = l->second.GetUtilities(); for(std::set::const_iterator util = tutils.begin(); util != tutils.end(); ++util) { // Record that this utility was used. used.insert(*util); // Don't emit the same utility twice for this target. if(emitted.insert(*util).second) { // Output this dependency. std::string utilType = *util + "_LIBRARY_TYPE"; const char* libType = m_Makefile->GetDefinition(utilType.c_str()); if ( libType ) { this->OutputLibDepend(fout, util->c_str()); } else { this->OutputExeDepend(fout, util->c_str()); } } } fout << "\n"; } } fout << "\n"; // Loop over the libraries used and make sure there is a rule to // build them in this makefile. If the library is in another // directory, add a rule to jump to that directory and make sure it // exists. for(std::set::const_iterator lib = used.begin(); lib != used.end(); ++lib) { // loop over the list of directories that the libraries might // be in, looking for an ADD_LIBRARY(lib...) line. This would // be stored in the cache std::string libPath = *lib + "_CMAKE_PATH"; const char* cacheValue = m_Makefile->GetDefinition(libPath.c_str()); // if cache and not the current directory add a rule, to // jump into the directory and build for the first time if(cacheValue && *cacheValue && (!this->SamePath(m_Makefile->GetCurrentOutputDirectory(), cacheValue))) { // add the correct extension std::string ltname = *lib+"_LIBRARY_TYPE"; const char* libType = m_Makefile->GetDefinition(ltname.c_str()); // if it was a library.. if (libType) { std::string library; std::string libpath = cacheValue; if(libType && std::string(libType) == "SHARED") { library = this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_PREFIX"); library += *lib; library += this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"); } else if(libType && std::string(libType) == "MODULE") { library = this->GetSafeDefinition("CMAKE_SHARED_MODULE_PREFIX"); library += *lib; library += this->GetSafeDefinition("CMAKE_SHARED_MODULE_SUFFIX"); } else if(libType && std::string(libType) == "STATIC") { library = this->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX"); library += *lib; library += this->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"); } else { cmSystemTools::Error("Unknown library type!"); return; } if(m_LibraryOutputPath.size()) { libpath = m_LibraryOutputPath; } else { libpath += "/"; } libpath += library; // put out a rule to build the library if it does not exist this->OutputBuildTargetInDir(fout, cacheValue, library.c_str(), libpath.c_str()); } // something other than a library... else { std::string exepath = cacheValue; if(m_ExecutableOutputPath.size()) { exepath = m_ExecutableOutputPath; } else { exepath += "/"; } std::string fullName = lib->c_str(); fullName += cmSystemTools::GetExecutableExtension(); exepath += fullName; this->OutputBuildTargetInDir(fout, cacheValue, fullName.c_str(), exepath.c_str()); } } } } void cmLocalUnixMakefileGenerator::OutputBuildTargetInDirWindows(std::ostream& fout, const char* path, const char* library, const char* fullpath) { std::string jumpBack = cmSystemTools::RelativePath(cmSystemTools::GetProgramPath(path).c_str(), m_Makefile->GetCurrentOutputDirectory()); jumpBack = this->ConvertToOutputForExisting(jumpBack.c_str()); std::string wpath = this->ConvertToOutputForExisting(path); std::string wfullpath = this->ConvertToOutputForExisting(fullpath); fout << wfullpath << ":\n\tcd " << wpath << "\n" << "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) cmake.depends\n" << "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) cmake.check_depends\n" << "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) -f cmake.check_depends\n" << "\t$(MAKE) $(MAKESILENT) " << library << "\n\tcd " << jumpBack << "\n"; } void cmLocalUnixMakefileGenerator::OutputBuildTargetInDir(std::ostream& fout, const char* path, const char* library, const char* fullpath) { if(m_WindowsShell) { this->OutputBuildTargetInDirWindows(fout, path, library, fullpath); return; } fout << this->ConvertToOutputForExisting(fullpath) << ":\n\tcd " << this->ConvertToOutputForExisting(path) << "; $(MAKE) $(MAKESILENT) cmake.depends" << "; $(MAKE) $(MAKESILENT) cmake.check_depends" << "; $(MAKE) $(MAKESILENT) -f cmake.check_depends" << "; $(MAKE) $(MAKESILENT) " << library << "\n\n"; } bool cmLocalUnixMakefileGenerator::SamePath(const char* path1, const char* path2) { if (strcmp(path1, path2) == 0) { return true; } #if defined(_WIN32) || defined(__APPLE__) return cmSystemTools::LowerCase(this->ConvertToOutputForExisting(path1)) == cmSystemTools::LowerCase(this->ConvertToOutputForExisting(path2)); #else return false; #endif } void cmLocalUnixMakefileGenerator::OutputLibDepend(std::ostream& fout, const char* name) { std::string libPath = name; libPath += "_CMAKE_PATH"; const char* cacheValue = m_Makefile->GetDefinition(libPath.c_str()); if( cacheValue && *cacheValue ) { // if there is a cache value, then this is a library that cmake // knows how to build, so we can depend on it std::string libpath; if (!this->SamePath(m_Makefile->GetCurrentOutputDirectory(), cacheValue)) { // if the library is not in the current directory, then get the full // path to it if(m_LibraryOutputPath.size()) { libpath = m_LibraryOutputPath; } else { libpath = cacheValue; libpath += "/"; } } else { // library is in current Makefile so use lib as a prefix libpath = m_LibraryOutputPath; } // add the correct extension std::string ltname = name; ltname += "_LIBRARY_TYPE"; const char* libType = m_Makefile->GetDefinition(ltname.c_str()); if(libType && std::string(libType) == "SHARED") { libpath += this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_PREFIX"); libpath += name; libpath += this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"); } else if (libType && std::string(libType) == "MODULE") { libpath += this->GetSafeDefinition("CMAKE_SHARED_MODULE_PREFIX"); libpath += name; libpath += this->GetSafeDefinition("CMAKE_SHARED_MODULE_SUFFIX"); } else if (libType && std::string(libType) == "STATIC") { libpath += this->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX"); libpath += name; libpath += this->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"); } fout << this->ConvertToRelativeOutputPath(libpath.c_str()) << " "; } } void cmLocalUnixMakefileGenerator::OutputExeDepend(std::ostream& fout, const char* name) { std::string exePath = name; exePath += "_CMAKE_PATH"; const char* cacheValue = m_Makefile->GetDefinition(exePath.c_str()); if( cacheValue && *cacheValue ) { // if there is a cache value, then this is a executable/utility that cmake // knows how to build, so we can depend on it std::string exepath; if (!this->SamePath(m_Makefile->GetCurrentOutputDirectory(), cacheValue)) { // if the exe/utility is not in the current directory, then get the full // path to it if(m_ExecutableOutputPath.size()) { exepath = m_ExecutableOutputPath; } else { exepath = cacheValue; exepath += "/"; } } else { // library is in current Makefile exepath = m_ExecutableOutputPath; } // add the library name exepath += name; // add the correct extension exepath += cmSystemTools::GetExecutableExtension(); fout << this->ConvertToRelativeOutputPath(exepath.c_str()) << " "; } // if it isn't in the cache, it might still be a utility target // so check for that else { std::map& targets = m_Makefile->GetTargets(); if (targets.find(name) != targets.end()) { fout << name << " "; } } } // fix up names of directories so they can be used // as targets in makefiles. inline std::string FixDirectoryName(const char* dir) { std::string s = dir; // replace ../ with 3 under bars size_t pos = s.find("../"); if(pos != std::string::npos) { s.replace(pos, 3, "___"); } // replace / directory separators with a single under bar pos = s.find("/"); while(pos != std::string::npos) { s.replace(pos, 1, "_"); pos = s.find("/"); } return s; } void cmLocalUnixMakefileGenerator:: BuildInSubDirectoryWindows(std::ostream& fout, const char* directory, const char* target1, const char* target2, bool silent) { std::string dir; if(target1) { dir = this->ConvertToOutputForExisting(directory); if(dir[0] == '\"') { dir = dir.substr(1, dir.size()-2); } fout << "\tif not exist \"" << dir << "\\$(NULL)\"" << " " << "$(MAKE) $(MAKESILENT) rebuild_cache\n"; if (!silent) { fout << "\t@echo " << directory << ": building " << target1 << "\n"; } fout << "\tcd " << dir << "\n" << "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) " << target1 << "\n"; } if(target2) { if (!silent) { fout << "\t@echo " << directory << ": building " << target2 << "\n"; } fout << "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) " << target2 << "\n"; } std::string currentDir = dir; cmSystemTools::ConvertToUnixSlashes(currentDir); std::string cdback = ".."; unsigned int i = 0; if(currentDir.size() > 2 && currentDir[0] == '.' && currentDir[1] == '/') { // start past ./ if it starts with ./ i = 2; } for(; i < currentDir.size(); ++i) { if(currentDir[i] == '/') { cdback += "/.."; } } fout << "\tcd " << this->ConvertToOutputForExisting(cdback.c_str()) << "\n\n"; } void cmLocalUnixMakefileGenerator::BuildInSubDirectory(std::ostream& fout, const char* dir, const char* target1, const char* target2, bool silent) { if(m_WindowsShell) { this->BuildInSubDirectoryWindows(fout, dir, target1, target2, silent); return; } std::string directory = this->ConvertToRelativeOutputPath(dir); if(target1) { fout << "\t@if test ! -d " << directory << "; then $(MAKE) rebuild_cache; fi\n"; if (!silent) { fout << "\t@echo " << directory << ": building " << target1 << "\n"; } fout << "\t@cd " << directory << "; $(MAKE) " << target1 << "\n"; } if(target2) { if (!silent) { fout << "\t@echo " << directory << ": building " << target2 << "\n"; } fout << "\t@cd " << directory << "; $(MAKE) " << target2 << "\n"; } fout << "\n"; } void cmLocalUnixMakefileGenerator:: OutputSubDirectoryVars(std::ostream& fout, const char* var, const char* target, const char* target1, const char* target2, const char* depend, const std::vector >& SubDirectories, bool silent) { if(!depend) { depend = ""; } if( SubDirectories.size() == 0) { return; } fout << "# Variable for making " << target << " in subdirectories.\n"; fout << var << " = "; unsigned int ii; for(ii =0; ii < SubDirectories.size(); ii++) { if(!SubDirectories[ii].second) { continue; } fout << " \\\n"; std::string subdir = FixDirectoryName(SubDirectories[ii].first.c_str()); fout << target << "_" << subdir.c_str(); } fout << " \n\n"; fout << "# Targets for making " << target << " in subdirectories.\n"; std::string last = ""; for(unsigned int cc =0; cc < SubDirectories.size(); cc++) { if(!SubDirectories[cc].second) { continue; } std::string subdir = FixDirectoryName(SubDirectories[cc].first.c_str()); fout << target << "_" << subdir.c_str() << ": " << depend; // Make each subdirectory depend on previous one. This forces // parallel builds (make -j 2) to build in same order as a single // threaded build to avoid dependency problems. if(cc > 0) { fout << " " << target << "_" << last.c_str(); } fout << "\n"; last = subdir; std::string dir = m_Makefile->GetCurrentOutputDirectory(); dir += "/"; dir += SubDirectories[cc].first; this->BuildInSubDirectory(fout, dir.c_str(), target1, target2, silent); } fout << "\n\n"; } // output rules for decending into sub directories void cmLocalUnixMakefileGenerator::OutputSubDirectoryRules(std::ostream& fout) { // Output Sub directory build rules const std::vector >& SubDirectories = m_Makefile->GetSubDirectories(); if( SubDirectories.size() == 0) { return; } this->OutputSubDirectoryVars(fout, "SUBDIR_BUILD", "default_target", "default_target", 0, "$(TARGETS)", SubDirectories, false); this->OutputSubDirectoryVars(fout, "SUBDIR_CLEAN", "clean", "clean", 0, 0, SubDirectories); this->OutputSubDirectoryVars(fout, "SUBDIR_DEPEND", "depend", "depend", 0, 0, SubDirectories); this->OutputSubDirectoryVars(fout, "SUBDIR_INSTALL", "install", "install", 0, 0, SubDirectories); } // Output the depend information for all the classes // in the makefile. These would have been generated // by the class cmMakeDepend GenerateMakefile bool cmLocalUnixMakefileGenerator::OutputObjectDepends(std::ostream& fout) { bool ret = false; // Iterate over every target. std::map& targets = m_Makefile->GetTargets(); for(std::map::const_iterator target = targets.begin(); target != targets.end(); ++target) { // Iterate over every source for this target. const std::vector& sources = target->second.GetSourceFiles(); for(std::vector::const_iterator source = sources.begin(); source != sources.end(); ++source) { if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY")) { if(!(*source)->GetDepends().empty()) { // Iterate through all the dependencies for this source. for(std::vector::const_iterator dep = (*source)->GetDepends().begin(); dep != (*source)->GetDepends().end(); ++dep) { std::string s = (*source)->GetSourceName(); s += this->GetOutputExtension((*source)->GetSourceExtension().c_str()); fout << this->ConvertToRelativeOutputPath(s.c_str()) << " : " << this->ConvertToRelativeOutputPath(dep->c_str()) << "\n"; ret = true; } fout << "\n\n"; } } } } return ret; } // Output the depend information for all the classes // in the makefile. These would have been generated // by the class cmMakeDepend GenerateMakefile void cmLocalUnixMakefileGenerator::OutputCheckDepends(std::ostream& fout) { std::set emittedLowerPath; std::set emitted; // Iterate over every target. std::map& targets = m_Makefile->GetTargets(); fout << "# Suppresses display of executed commands\n"; fout << ".SILENT:\n"; fout << "# disable some common implicit rules to speed things up\n"; fout << ".SUFFIXES:\n"; fout << ".SUFFIXES:.hpuxmakemusthaverule\n"; this->OutputMakeVariables(fout); fout << "default:\n"; fout << "\t$(MAKE) $(MAKESILENT) -f cmake.check_depends all\n" << "\t$(MAKE) $(MAKESILENT) -f cmake.check_depends cmake.depends\n\n"; for(std::map::const_iterator target = targets.begin(); target != targets.end(); ++target) { // Iterate over every source for this target. const std::vector& sources = target->second.GetSourceFiles(); for(std::vector::const_iterator source = sources.begin(); source != sources.end(); ++source) { if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY")) { if(!(*source)->GetDepends().empty()) { for(std::vector::const_iterator dep = (*source)->GetDepends().begin(); dep != (*source)->GetDepends().end(); ++dep) { // do not call CollapseFullPath on dep here, because it already // has been done because m_FullPath on cmDependInformation // always is it called. If it is called here, network builds are // very slow because of the number of stats std::string dependfile = this->ConvertToRelativeOutputPath(dep->c_str()); // use the lower path function to create uniqe names std::string lowerpath = this->LowerCasePath(dependfile.c_str()); if(emittedLowerPath.insert(lowerpath).second) { emitted.insert(dependfile); fout << "all: " << dependfile << "\n"; } } } } } } fout << "\n\n# if any of these files changes run make dependlocal\n"; std::set::iterator i; for(i = emitted.begin(); i != emitted.end(); ++i) { fout << "cmake.depends: " << *i << "\n"; } fout << "cmake.depends: \n" << "\t$(MAKE) $(MAKESILENT) dependlocal\n\n"; fout << "\n\n"; fout << "# if a .h file is removed then run make dependlocal\n\n"; for(std::set::iterator it = emitted.begin(); it != emitted.end(); ++it) { fout << *it << ":\n" << "\t$(MAKE) $(MAKESILENT) dependlocal\n\n"; } } // Output each custom rule in the following format: // output: source depends... // (tab) command... void cmLocalUnixMakefileGenerator::OutputCustomRules(std::ostream& fout) { // 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 processedOutputs; // first output all custom rules const std::vector& sources = m_Makefile->GetSourceFiles(); for(std::vector::const_iterator i = sources.begin(); i != sources.end(); ++i) { if ((*i)->GetCustomCommand()) { cmCustomCommand *c = (*i)->GetCustomCommand(); // escape spaces and convert to native slashes path for // the command std::string comment = c->GetComment(); std::string command = c->GetCommand(); cmSystemTools::ReplaceString(command, "/./", "/"); command = this->ConvertToRelativeOutputPath(command.c_str()); command += " "; // now add the arguments command += c->GetArguments(); std::vector depends; // Collect out all the dependencies for this rule. for(std::vector::const_iterator d = c->GetDepends().begin(); d != c->GetDepends().end(); ++d) { 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 && *cacheValue ) { libPath = cacheValue; if (m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH") && m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH")[0] != '\0') { libPath = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"); } libPath += "/"; libPath += dep; libPath += cmSystemTools::GetExecutableExtension(); dep = libPath; } cmSystemTools::ReplaceString(dep, "/./", "/"); cmSystemTools::ReplaceString(dep, "/$(IntDir)/", "/"); dep = this->ConvertToRelativeOutputPath(dep.c_str()); depends.push_back(dep.c_str()); } // output rule if (processedOutputs.find(c->GetOutput()) == processedOutputs.end()) { this->OutputMakeRule(fout, (comment.size()?comment.c_str():"Custom command"), c->GetOutput().c_str(), depends, 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()); } } } } std::string cmLocalUnixMakefileGenerator::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; } void cmLocalUnixMakefileGenerator::OutputMakeVariables(std::ostream& fout) { const char* variables = "# the standard shell for make\n" "SHELL = /bin/sh\n" "\n"; if(!m_WindowsShell) { fout << variables; } else { fout << "!IF \"$(OS)\" == \"Windows_NT\"\n" "NULL=\n" "!ELSE \n" "NULL=nul\n" "!ENDIF \n"; } if(m_MakeSilentFlag.size()) { fout << "MAKESILENT = " << m_MakeSilentFlag << "\n"; } std::string cmakecommand = this->ConvertToOutputForExisting( m_Makefile->GetDefinition("CMAKE_COMMAND")); fout << "CMAKE_COMMAND = " << cmakecommand << "\n"; fout << "RM = " << cmakecommand.c_str() << " -E remove -f\n"; if(m_Makefile->GetDefinition("CMAKE_EDIT_COMMAND")) { fout << "CMAKE_EDIT_COMMAND = " << this->ConvertToOutputForExisting(m_Makefile->GetDefinition("CMAKE_EDIT_COMMAND")) << "\n"; } fout << "CMAKE_CURRENT_SOURCE = " << this->ConvertToRelativeOutputPath(m_Makefile->GetStartDirectory()) << "\n"; fout << "CMAKE_CURRENT_BINARY = " << this->ConvertToRelativeOutputPath(m_Makefile->GetStartOutputDirectory()) << "\n"; fout << "CMAKE_SOURCE_DIR = " << this->ConvertToRelativeOutputPath(m_Makefile->GetHomeDirectory()) << "\n"; fout << "CMAKE_BINARY_DIR = " << this->ConvertToRelativeOutputPath(m_Makefile->GetHomeOutputDirectory()) << "\n"; // Output Include paths fout << "INCLUDE_FLAGS = "; std::vector& includes = m_Makefile->GetIncludeDirectories(); std::vector::iterator i; fout << "-I" << this->ConvertToOutputForExisting(m_Makefile->GetStartDirectory()) << " "; 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(include != "/usr/include") { fout << "-I" << this->ConvertToOutputForExisting(i->c_str()) << " "; } } fout << m_Makefile->GetDefineFlags(); fout << "\n\n"; } void cmLocalUnixMakefileGenerator::OutputInstallRules(std::ostream& fout) { // Install is not currently supported on windows if(m_WindowsShell) { return; } std::string cmakecommand = this->ConvertToOutputForExisting( m_Makefile->GetDefinition("CMAKE_COMMAND")); const char* root = m_Makefile->GetDefinition("CMAKE_ROOT"); fout << "INSTALL = \"" << root << "/Templates/install-sh\" -c\n"; fout << "INSTALL_PROGRAM = $(INSTALL)\n"; fout << "INSTALL_DATA = $(INSTALL) -m 644\n"; const cmTargets &tgts = m_Makefile->GetTargets(); fout << "install: $(SUBDIR_INSTALL)\n"; fout << "\t@echo \"Installing ...\"\n"; const char* prefix = m_Makefile->GetDefinition("CMAKE_INSTALL_PREFIX"); if (!prefix) { prefix = "/usr/local"; } for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); l++) { if (l->second.GetInstallPath() != "") { // first make the directories for each target fout << "\t@if [ ! -d \"$(DESTDIR)" << prefix << l->second.GetInstallPath() << "\" ] ; then \\\n"; fout << "\t echo \"Making directory \\\"$(DESTDIR)" << prefix << l->second.GetInstallPath() << "\\\" \"; \\\n"; fout << "\t mkdir -p \"$(DESTDIR)" << prefix << l->second.GetInstallPath() << "\"; \\\n"; fout << "\t chmod 755 \"$(DESTDIR)" << prefix << l->second.GetInstallPath() << "\"; \\\n"; fout << "\t else true; \\\n"; fout << "\t fi\n"; std::string fname; // now install the target switch (l->second.GetType()) { case cmTarget::STATIC_LIBRARY: case cmTarget::SHARED_LIBRARY: case cmTarget::MODULE_LIBRARY: { std::string targetName; std::string targetNameSO; std::string targetNameReal; std::string targetNameBase; this->GetLibraryNames(l->first.c_str(), l->second, targetName, targetNameSO, targetNameReal, targetNameBase); std::string installName = "$(DESTDIR)"; installName += prefix; installName += l->second.GetInstallPath(); installName += "/"; std::string installNameSO = installName; std::string installNameReal = installName; installName += targetName; installNameSO += targetNameSO; installNameReal += targetNameReal; fname = m_LibraryOutputPath; fname += targetNameReal; fout << "\t$(INSTALL_DATA) " << this->ConvertToRelativeOutputPath(fname.c_str()) << " \"$(DESTDIR)" << prefix << l->second.GetInstallPath() << "\"\n"; fout << "\t" << cmakecommand << " -E cmake_symlink_library \"" << installNameReal << "\" \"" << installNameSO << "\" \"" << installName << "\"\n"; }; break; case cmTarget::EXECUTABLE: fname = m_ExecutableOutputPath; fname += this->GetFullTargetName(l->first.c_str(), l->second); fout << "\t$(INSTALL_PROGRAM) " << this->ConvertToRelativeOutputPath(fname.c_str()) << " \"$(DESTDIR)" << prefix << l->second.GetInstallPath() << "\"\n"; break; case cmTarget::INSTALL_FILES: { std::string sourcePath = m_Makefile->GetCurrentDirectory(); std::string binaryPath = m_Makefile->GetCurrentOutputDirectory(); sourcePath += "/"; binaryPath += "/"; const std::vector &sf = l->second.GetSourceLists(); std::vector::const_iterator i; for (i = sf.begin(); i != sf.end(); ++i) { std::string f = *i; if(f.substr(0, sourcePath.length()) == sourcePath) { f = f.substr(sourcePath.length()); } else if(f.substr(0, binaryPath.length()) == binaryPath) { f = f.substr(binaryPath.length()); } fout << "\t@echo \"Installing " << f.c_str() << " \"\n"; // avoid using install-sh to install install-sh // does not work on windows.... if(*i == "install-sh") { fout << "\tcp "; } else { fout << "\t$(INSTALL_DATA) "; } fout << this->ConvertToRelativeOutputPath(i->c_str()) << " \"$(DESTDIR)" << prefix << l->second.GetInstallPath() << "\"\n"; } } break; case cmTarget::INSTALL_PROGRAMS: { std::string sourcePath = m_Makefile->GetCurrentDirectory(); std::string binaryPath = m_Makefile->GetCurrentOutputDirectory(); sourcePath += "/"; binaryPath += "/"; const std::vector &sf = l->second.GetSourceLists(); std::vector::const_iterator i; for (i = sf.begin(); i != sf.end(); ++i) { std::string f = *i; if(f.substr(0, sourcePath.length()) == sourcePath) { f = f.substr(sourcePath.length()); } else if(f.substr(0, binaryPath.length()) == binaryPath) { f = f.substr(binaryPath.length()); } fout << "\t@echo \"Installing " << f.c_str() << " \"\n"; // avoid using install-sh to install install-sh // does not work on windows.... if(*i == "install-sh") { fout << "\t @cp "; } else { fout << "\t @$(INSTALL_PROGRAM) "; } fout << this->ConvertToRelativeOutputPath(i->c_str()) << " \"$(DESTDIR)" << prefix << l->second.GetInstallPath() << "\"\n"; } } break; case cmTarget::UTILITY: default: break; } } } } void cmLocalUnixMakefileGenerator::OutputMakeRules(std::ostream& fout) { this->OutputMakeRule(fout, "default build rule", "all", "cmake.depends $(TARGETS) $(SUBDIR_BUILD)", 0); this->OutputMakeRule(fout, "clean generated files", "clean", "$(SUBDIR_CLEAN)", "-@ $(RM) $(CLEAN_OBJECT_FILES) " " $(TARGETS) $(TARGET_EXTRAS) $(GENERATED_QT_FILES) $(GENERATED_FLTK_FILES)"); // collect up all the sources std::vector allsources; std::map& targets = m_Makefile->GetTargets(); for(std::map::const_iterator target = targets.begin(); target != targets.end(); ++target) { // Iterate over every source for this target. const std::vector& sources = target->second.GetSourceFiles(); for(std::vector::const_iterator source = sources.begin(); source != sources.end(); ++source) { if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY")) { allsources.push_back(this->ConvertToRelativeOutputPath((*source)->GetFullPath().c_str())); } } } std::string checkCache = m_Makefile->GetHomeOutputDirectory(); checkCache += "/cmake.check_cache"; checkCache = this->ConvertToRelativeOutputPath(checkCache.c_str()); std::vector cmake_depends; cmake_depends.push_back(checkCache); cmake_depends.push_back("$(CMAKE_MAKEFILE_SOURCES)"); this->OutputMakeRule(fout, "dependencies.", "cmake.depends", cmake_depends, "$(CMAKE_COMMAND) " "-S$(CMAKE_CURRENT_SOURCE) -O$(CMAKE_CURRENT_BINARY) " "-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"); this->OutputMakeRule(fout, "dependencies", "cmake.check_depends", allsources, "$(CMAKE_COMMAND) " "-S$(CMAKE_CURRENT_SOURCE) -O$(CMAKE_CURRENT_BINARY) " "-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"); this->OutputMakeRule(fout, "dependencies", "depend", "$(SUBDIR_DEPEND)", "$(CMAKE_COMMAND) " "-S$(CMAKE_CURRENT_SOURCE) -O$(CMAKE_CURRENT_BINARY) " "-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"); this->OutputMakeRule(fout, "dependencies", "dependlocal", 0, "$(CMAKE_COMMAND) " "-S$(CMAKE_CURRENT_SOURCE) -O$(CMAKE_CURRENT_BINARY) " "-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"); this->OutputMakeRule(fout, "CMakeCache.txt", "rebuild_cache", 0, "$(CMAKE_COMMAND) " "-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"); std::vector check_cache_depends; std::string CMakeCache = m_Makefile->GetHomeOutputDirectory(); CMakeCache += "/CMakeCache.txt"; CMakeCache = this->ConvertToRelativeOutputPath(CMakeCache.c_str()); check_cache_depends.push_back(CMakeCache); check_cache_depends.push_back("$(CMAKE_MAKEFILE_SOURCES)"); this->OutputMakeRule(fout, "CMakeCache.txt because out-of-date:", checkCache.c_str(), check_cache_depends, "$(CMAKE_COMMAND) " "-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"); // if CMAKE_EDIT_COMMAND is defined then add a rule to run it // called edit_cache if(m_Makefile->GetDefinition("CMAKE_EDIT_COMMAND")) { this->OutputMakeRule(fout, "edit CMakeCache.txt", "edit_cache", 0, "$(CMAKE_EDIT_COMMAND) " "-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"); } else { this->OutputMakeRule(fout, "edit CMakeCache.txt", "edit_cache", 0, "$(CMAKE_COMMAND) " "-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) -i"); } this->OutputMakeRule(fout, "CMakeCache.txt", "$(CMAKE_BINARY_DIR)/CMakeCache.txt", 0, "$(CMAKE_COMMAND) " "-H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"); this->OutputMakeRule(fout, "Rule to keep make from removing Makefiles " "if control-C is hit during a run of cmake.", ".PRECIOUS", "Makefile cmake.depends", 0); this->OutputSourceObjectBuildRules(fout); // find ctest std::string ctest = m_Makefile->GetDefinition("CMAKE_COMMAND"); ctest = cmSystemTools::GetFilenamePath(ctest.c_str()); ctest += "/"; ctest += "ctest"; ctest += cmSystemTools::GetExecutableExtension(); if(!cmSystemTools::FileExists(ctest.c_str())) { ctest = m_Makefile->GetDefinition("CMAKE_COMMAND"); ctest = cmSystemTools::GetFilenamePath(ctest.c_str()); ctest += "/Debug/"; ctest += "ctest"; ctest += cmSystemTools::GetExecutableExtension(); } if(!cmSystemTools::FileExists(ctest.c_str())) { ctest = m_Makefile->GetDefinition("CMAKE_COMMAND"); ctest = cmSystemTools::GetFilenamePath(ctest.c_str()); ctest += "/Release/"; ctest += "ctest"; ctest += cmSystemTools::GetExecutableExtension(); } if (!cmSystemTools::FileExists(ctest.c_str())) { if ( !m_Makefile->GetDefinition("PROJECT_NAME") || strcmp(m_Makefile->GetDefinition("PROJECT_NAME"), "CMake") ) { return; } ctest = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"); ctest += "/ctest"; } if (m_Makefile->IsOn("CMAKE_TESTING_ENABLED")) { fout << "ARGS=\n"; std::string cmd = this->ConvertToOutputForExisting(ctest.c_str()); cmd += " $(ARGS)"; this->OutputMakeRule(fout, "tests", "test", "", cmd.c_str()); } } void cmLocalUnixMakefileGenerator:: OutputBuildObjectFromSource(std::ostream& fout, const char* shortName, const cmSourceFile& source, const char* extraCompileFlags, bool shared) { // Header files shouldn't have build rules. if(source.GetPropertyAsBool("HEADER_FILE_ONLY")) { return; } std::string comment = "object file"; std::string objectFile = std::string(shortName) + this->GetOutputExtension(source.GetSourceExtension().c_str()); objectFile = this->ConvertToRelativeOutputPath(objectFile.c_str()); cmSystemTools::FileFormat format = cmSystemTools::GetFileFormat(source.GetSourceExtension().c_str()); std::vector rules; std::string flags; if(extraCompileFlags) { flags += extraCompileFlags; } std::string sourceFile = this->ConvertToRelativeOutputPath(source.GetFullPath().c_str()); std::string buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); buildType = cmSystemTools::UpperCase(buildType); switch(format) { case cmSystemTools::C_FILE_FORMAT: { rules.push_back(m_Makefile->GetDefinition("CMAKE_C_COMPILE_OBJECT")); flags += this->GetSafeDefinition("CMAKE_C_FLAGS"); flags += " "; if(buildType.size()) { std::string build = "CMAKE_C_FLAGS_"; build += buildType; flags += this->GetSafeDefinition(build.c_str()); flags += " "; } if(shared) { flags += this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_C_FLAGS"); flags += " "; } if(cmSystemTools::IsOn(m_Makefile->GetDefinition("BUILD_SHARED_LIBS"))) { flags += this->GetSafeDefinition("CMAKE_SHARED_BUILD_C_FLAGS"); flags += " "; } break; } case cmSystemTools::CXX_FILE_FORMAT: { rules.push_back(m_Makefile->GetDefinition("CMAKE_CXX_COMPILE_OBJECT")); flags += this->GetSafeDefinition("CMAKE_CXX_FLAGS"); flags += " "; if(buildType.size()) { std::string build = "CMAKE_CXX_FLAGS_"; build += buildType; flags += this->GetSafeDefinition(build.c_str()); flags += " "; } if(shared) { flags += this->GetSafeDefinition("CMAKE_SHARED_LIBRARY_CXX_FLAGS"); flags += " "; } if(cmSystemTools::IsOn(m_Makefile->GetDefinition("BUILD_SHARED_LIBS"))) { flags += this->GetSafeDefinition("CMAKE_SHARED_BUILD_CXX_FLAGS"); flags += " "; } break; } case cmSystemTools::HEADER_FILE_FORMAT: return; case cmSystemTools::DEFINITION_FILE_FORMAT: return; case cmSystemTools::RESOURCE_FILE_FORMAT: { flags = " $(INCLUDE_FLAGS) "; // use rc rule here if it is defined const char* rule = m_Makefile->GetDefinition("CMAKE_COMPILE_RESOURCE"); if(rule) { rules.push_back(rule); } } break; case cmSystemTools::NO_FILE_FORMAT: case cmSystemTools::JAVA_FILE_FORMAT: case cmSystemTools::STATIC_LIBRARY_FILE_FORMAT: case cmSystemTools::SHARED_LIBRARY_FILE_FORMAT: case cmSystemTools::MODULE_FILE_FORMAT: case cmSystemTools::OBJECT_FILE_FORMAT: case cmSystemTools::UNKNOWN_FILE_FORMAT: cmSystemTools::Error("Unexpected file type ", sourceFile.c_str()); break; } flags += "$(INCLUDE_FLAGS) "; // expand multi-command semi-colon separated lists // of commands into separate commands std::vector commands; cmSystemTools::ExpandList(rules, commands); for(std::vector::iterator i = commands.begin(); i != commands.end(); ++i) { this->ExpandRuleVariables(*i, 0, // no objects 0, // no target 0, // no link libs sourceFile.c_str(), objectFile.c_str(), flags.c_str()); } std::vector sourceAndDeps; sourceAndDeps.push_back(sourceFile); // Check for extra object-file dependencies. std::vector depends; const char* additionalDeps = source.GetProperty("OBJECT_DEPENDS"); if(additionalDeps) { cmSystemTools::ExpandListArgument(additionalDeps, depends); for(std::vector::iterator i = depends.begin(); i != depends.end(); ++i) { sourceAndDeps.push_back(this->ConvertToRelativeOutputPath(i->c_str())); } } this->OutputMakeRule(fout, comment.c_str(), objectFile.c_str(), sourceAndDeps, commands); } void cmLocalUnixMakefileGenerator::OutputSourceObjectBuildRules(std::ostream& fout) { fout << "# Rules to build " << this->GetOutputExtension("") << " files from their sources:\n"; std::set rules; // Iterate over every target. std::map& targets = m_Makefile->GetTargets(); for(std::map::const_iterator target = targets.begin(); target != targets.end(); ++target) { bool shared = ((target->second.GetType() == cmTarget::SHARED_LIBRARY) || (target->second.GetType() == cmTarget::MODULE_LIBRARY)); std::string exportsDef = ""; if(shared) { std::string export_symbol; if (const char* custom_export_name = target->second.GetProperty("DEFINE_SYMBOL")) { export_symbol = custom_export_name; } else { std::string in = target->first + "_EXPORTS"; export_symbol = cmSystemTools::MakeCindentifier(in.c_str()); } exportsDef = "-D"+ export_symbol; } // Iterate over every source for this target. const std::vector& sources = target->second.GetSourceFiles(); for(std::vector::const_iterator source = sources.begin(); source != sources.end(); ++source) { if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY") && !(*source)->GetCustomCommand()) { std::string shortName; std::string sourceName; // If the full path to the source file includes this // 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)) { sourceName = (*source)->GetSourceName()+"."+ (*source)->GetSourceExtension(); shortName = (*source)->GetSourceName(); // The path may be relative. See if a directory needs to be // created for the output file. This is a ugly, and perhaps // should be moved elsewhere. std::string relPath = cmSystemTools::GetFilenamePath((*source)->GetSourceName()); if(relPath != "") { std::string outPath = m_Makefile->GetCurrentOutputDirectory(); outPath += "/"+relPath; cmSystemTools::MakeDirectory(outPath.c_str()); } } else { sourceName = (*source)->GetFullPath(); shortName = cmSystemTools::GetFilenameName((*source)->GetSourceName()); } std::string shortNameWithExt = shortName + (*source)->GetSourceExtension(); // Only output a rule for each .o once. std::string compileFlags = exportsDef; compileFlags += " "; if(rules.find(shortNameWithExt) == rules.end()) { if((*source)->GetProperty("COMPILE_FLAGS")) { compileFlags += (*source)->GetProperty("COMPILE_FLAGS"); compileFlags += " "; } this->OutputBuildObjectFromSource(fout, shortName.c_str(), *(*source), compileFlags.c_str(), shared); rules.insert(shortNameWithExt); } } } } } void cmLocalUnixMakefileGenerator::OutputMakeRule(std::ostream& fout, const char* comment, const char* target, const char* depends, const char* command, const char* command2, const char* command3, const char* command4) { std::vector commands; if(command) { commands.push_back(command); } if(command2) { commands.push_back(command2); } if(command3) { commands.push_back(command3); } if(command4) { commands.push_back(command4); } this->OutputMakeRule(fout, comment, target, depends, commands); } void cmLocalUnixMakefileGenerator::OutputMakeRule(std::ostream& fout, const char* comment, const char* target, const char* depends, const std::vector& commands) { std::vector depend; if(depends) { depend.push_back(depends); } this->OutputMakeRule(fout, comment, target, depend, commands); } void cmLocalUnixMakefileGenerator::OutputMakeRule(std::ostream& fout, const char* comment, const char* target, const std::vector& depends, const char* command) { std::vector commands; if(command) { commands.push_back(command); } this->OutputMakeRule(fout, comment, target, depends, commands); } void cmLocalUnixMakefileGenerator::OutputMakeRule(std::ostream& fout, const char* comment, const char* target, const std::vector& depends, const std::vector& commands) { if(!target) { cmSystemTools::Error("no target for OutputMakeRule"); return; } std::string replace; if(comment) { replace = comment; m_Makefile->ExpandVariablesInString(replace); fout << "#---------------------------------------------------------\n"; fout << "# " << replace; fout << "\n#\n"; } fout << "\n"; replace = target; m_Makefile->ExpandVariablesInString(replace); std::string tgt = this->ConvertToRelativeOutputPath(replace.c_str()); tgt = this->ConvertToMakeTarget(tgt.c_str()); if(depends.empty()) { fout << tgt.c_str() << ":\n"; } else { // Split dependencies into multiple rule lines. This allows for // very long dependency lists. for(std::vector::const_iterator dep = depends.begin(); dep != depends.end(); ++dep) { replace = *dep; m_Makefile->ExpandVariablesInString(replace); replace = this->ConvertToMakeTarget(replace.c_str()); fout << tgt.c_str() << ": " << replace.c_str() << "\n"; } } int count = 0; for (std::vector::const_iterator i = commands.begin(); i != commands.end(); ++i) { replace = *i; m_Makefile->ExpandVariablesInString(replace); if(count == 0 && replace.find_first_not_of(" \t\n\r") != std::string::npos && replace[0] != '-' && replace.find("echo") != 0 && replace.find("$(MAKE)") != 0) { std::string echostring = "Building "; echostring += comment; echostring += " "; echostring += target; echostring += "..."; this->OutputEcho(fout,echostring.c_str()); } fout << "\t" << replace.c_str() << "\n"; count++; } fout << "\n"; } const char* cmLocalUnixMakefileGenerator::GetSafeDefinition(const char* def) { const char* ret = m_Makefile->GetDefinition(def); if(!ret) { return ""; } return ret; } std::string cmLocalUnixMakefileGenerator::LowerCasePath(const char* path) { #ifdef _WIN32 return cmSystemTools::LowerCase(path); #else return std::string(path); #endif } std::string cmLocalUnixMakefileGenerator::CreateMakeVariable(const char* sin, const char* s2in) { std::string s = sin; std::string s2 = s2in; std::string unmodified = s; unmodified += s2; // if there is no restriction on the length of make variables // and there are no "." charactors in the string, then return the // unmodified combination. if(!m_MakefileVariableSize && unmodified.find('.') == s.npos) { return unmodified; } // see if the variable has been defined before and return // the modified version of the variable std::map::iterator i = m_MakeVariableMap.find(unmodified); if(i != m_MakeVariableMap.end()) { return i->second; } // start with the unmodified variable std::string ret = unmodified; // if this there is no value for m_MakefileVariableSize then // the string must have bad characters in it if(!m_MakefileVariableSize) { cmSystemTools::ReplaceString(ret, ".", "_"); int ni = 0; char buffer[5]; // make sure the _ version is not already used, if // it is used then add number to the end of the variable while(m_ShortMakeVariableMap.count(ret) && ni < 1000) { ++ni; sprintf(buffer, "%04d", ni); ret = unmodified + buffer; } m_ShortMakeVariableMap[ret] = "1"; m_MakeVariableMap[unmodified] = ret; return ret; } // if the string is greater the 32 chars it is an invalid vairable name // for borland make if(static_cast(ret.size()) > m_MakefileVariableSize) { int keep = m_MakefileVariableSize - 8; int size = keep + 3; std::string str1 = s; std::string str2 = s2; // we must shorten the combined string by 4 charactors // keep no more than 24 charactors from the second string if(static_cast(str2.size()) > keep) { str2 = str2.substr(0, keep); } if(static_cast(str1.size()) + static_cast(str2.size()) > size) { str1 = str1.substr(0, size - str2.size()); } char buffer[5]; int ni = 0; sprintf(buffer, "%04d", ni); ret = str1 + str2 + buffer; while(m_ShortMakeVariableMap.count(ret) && ni < 1000) { ++ni; sprintf(buffer, "%04d", ni); ret = str1 + str2 + buffer; } if(ni == 1000) { cmSystemTools::Error("Borland makefile variable length too long"); return unmodified; } // once an unused variable is found m_ShortMakeVariableMap[ret] = "1"; } // always make an entry into the unmodified to variable map m_MakeVariableMap[unmodified] = ret; return ret; } void cmLocalUnixMakefileGenerator::GetLibraryNames(const char* n, const cmTarget& t, std::string& name, std::string& soName, std::string& realName, std::string& baseName) { // Check for library version properties. const char* version = t.GetProperty("VERSION"); const char* soversion = t.GetProperty("SOVERSION"); if((t.GetType() != cmTarget::SHARED_LIBRARY && t.GetType() != cmTarget::MODULE_LIBRARY) || !m_Makefile->GetDefinition("CMAKE_SHARED_LIBRARY_SONAME_C_FLAG")) { // Versioning is supported only for shared libraries and modules, // and then only when the platform supports an soname flag. version = 0; soversion = 0; } if(version && !soversion) { // The soversion must be set if the library version is set. Use // the library version as the soversion. soversion = version; } // The library name. name = this->GetFullTargetName(n, t); // The library's soname. soName = name; if(soversion) { soName += "."; soName += soversion; } // The library's real name on disk. realName = name; if(version) { realName += "."; realName += version; } else if(soversion) { realName += "."; realName += soversion; } // The library name without extension. baseName = this->GetBaseTargetName(n, t); } std::string cmLocalUnixMakefileGenerator::ConvertToMakeTarget(const char* tgt) { // Make targets should not have a leading './' for a file in the // directory containing the makefile. std::string ret = tgt; if(ret.size() > 2 && (ret[0] == '.') && ( (ret[1] == '/') || ret[1] == '\\')) { std::string upath = ret; cmSystemTools::ConvertToUnixSlashes(upath); if(upath.find(2, '/') == upath.npos) { ret = ret.substr(2, ret.size()-2); } } return ret; }