From 537e2b4ed57d5a84f140f9b9bde427e7b604b330 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 16 Feb 2006 15:19:00 -0500 Subject: ENH: Implemented RPATH specification support. It is documented by the command SET_TARGET_PROPERTIES. --- Source/cmGlobalUnixMakefileGenerator3.cxx | 24 ++++++ Source/cmLocalGenerator.cxx | 50 +++++++++--- Source/cmLocalGenerator.h | 2 +- Source/cmLocalUnixMakefileGenerator3.cxx | 18 ++++- Source/cmMakefileExecutableTargetGenerator.cxx | 20 ++++- Source/cmMakefileExecutableTargetGenerator.h | 2 +- Source/cmMakefileLibraryTargetGenerator.cxx | 57 ++++++++++---- Source/cmMakefileLibraryTargetGenerator.h | 7 +- Source/cmSetTargetPropertiesCommand.h | 15 +++- Source/cmTarget.cxx | 101 +++++++++++++++++++++++++ Source/cmTarget.h | 16 +++- Tests/SimpleInstall/CMakeLists.txt | 3 + Tests/SimpleInstallS2/CMakeLists.txt | 3 + 13 files changed, 278 insertions(+), 40 deletions(-) diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 1acea61..70c0ed4 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -152,6 +152,11 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() "The main recursive all target", "all", depends, no_commands, true); + // Write an empty preinstall: + lg->WriteMakeRule(makefileStream, + "The main recursive preinstall target", "preinstall", + depends, no_commands, true); + lg->WriteMakeVariables(makefileStream); // Write out the "special" stuff @@ -731,6 +736,25 @@ cmGlobalUnixMakefileGenerator3 lg->WriteMakeRule(ruleFileStream, "Convenience name for target.", t->second.GetName(), depends, commands, true); + // Add rules to prepare the target for installation. + if(t->second.NeedRelinkBeforeInstall()) + { + localName = lg->GetRelativeTargetDirectory(t->second); + localName += "/preinstall"; + depends.clear(); + commands.clear(); + commands.push_back(lg->GetRecursiveMakeCall + (makefileName.c_str(), localName.c_str())); + this->AppendGlobalTargetDepends(depends,t->second); + lg->WriteMakeRule(ruleFileStream, "Pre-intsall relink rule for target.", + localName.c_str(), depends, commands, true); + depends.clear(); + depends.push_back(localName); + commands.clear(); + lg->WriteMakeRule(ruleFileStream, "Prepare target for install.", + "preinstall", depends, commands, true); + } + // add the clean rule localName = lg->GetRelativeTargetDirectory(t->second); makeTargetName = localName; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 4a95ca1..42738f9 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -353,6 +353,7 @@ void cmLocalGenerator::GenerateInstallRules() // EXECUTABLE_OUTPUT_PATH not defined exeOutPath = currdir + "/"; } + std::string relinkDir = currdir + "/CMakeFiles/CMakeRelink.dir/"; // Include user-specified install scripts. std::vector const& installScripts = @@ -375,6 +376,7 @@ void cmLocalGenerator::GenerateInstallRules() } if (l->second.GetInstallPath() != "") { + bool need_relink = l->second.NeedRelinkBeforeInstall(); destination = "${CMAKE_INSTALL_PREFIX}" + l->second.GetInstallPath(); cmSystemTools::ConvertToUnixSlashes(destination); const char* dest = destination.c_str(); @@ -398,7 +400,7 @@ void cmLocalGenerator::GenerateInstallRules() if ( ext == ".dll" ) { // Install the .lib separately. - std::string libname = libOutPath; + std::string libname = need_relink? relinkDir : libOutPath; libname += this->GetInstallReference(l->second, config, configurationTypes, true); @@ -438,7 +440,7 @@ void cmLocalGenerator::GenerateInstallRules() case cmTarget::STATIC_LIBRARY: case cmTarget::MODULE_LIBRARY: { - fname = libOutPath; + fname = need_relink? relinkDir : libOutPath; fname += this->GetInstallReference(l->second, config, configurationTypes); files = fname.c_str(); @@ -460,7 +462,7 @@ void cmLocalGenerator::GenerateInstallRules() } std::string exeName = this->GetInstallReference(l->second, config, configurationTypes); - fname = exeOutPath; + fname = need_relink? relinkDir : exeOutPath; fname += exeName; if(l->second.GetPropertyAsBool("MACOSX_BUNDLE")) { @@ -1117,7 +1119,11 @@ const char* cmLocalGenerator::GetIncludeFlags(const char* lang) } flags += m_Makefile->GetDefineFlags(); m_LanguageToIncludeFlags[lang] = flags; - return m_LanguageToIncludeFlags[lang].c_str(); + + // Use this temorary variable for the return value to work-around a + // bogus GCC 2.95 warning. + const char* ret = m_LanguageToIncludeFlags[lang].c_str(); + return ret; } //---------------------------------------------------------------------------- @@ -1246,7 +1252,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, linkFlags += " "; } cmOStringStream linklibsStr; - this->OutputLinkLibraries(linklibsStr, target); + this->OutputLinkLibraries(linklibsStr, target, false); linkLibs = linklibsStr.str(); } break; @@ -1279,7 +1285,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, flags += m_Makefile->GetSafeDefinition(sharedFlagsVar.c_str()); flags += " "; cmOStringStream linklibs; - this->OutputLinkLibraries(linklibs, target); + this->OutputLinkLibraries(linklibs, target, false); linkLibs = linklibs.str(); if(cmSystemTools::IsOn(m_Makefile->GetDefinition("BUILD_SHARED_LIBS"))) { @@ -1319,7 +1325,8 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, * to the name of the library. This will not link a library against itself. */ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout, - cmTarget &tgt) + cmTarget& tgt, + bool relink) { // Try to emit each search path once std::set emitted; @@ -1327,7 +1334,6 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout, bool outputRuntime = true; std::string runtimeFlag; std::string runtimeSep; - std::vector runtimeDirs; const char* config = m_Makefile->GetDefinition("CMAKE_BUILD_TYPE"); const char* linkLanguage = tgt.GetLinkerLanguage(this->GetGlobalGenerator()); @@ -1347,7 +1353,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout, // concatenate all paths or no? bool runtimeConcatenate = ( runtimeSep!="" ); - if(runtimeFlag == "" || m_Makefile->IsOn("CMAKE_SKIP_RPATH") ) + if(runtimeFlag == "" || m_Makefile->IsOn("CMAKE_SKIP_RPATH")) { outputRuntime = false; } @@ -1375,6 +1381,28 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout, std::vector libDirs; this->ComputeLinkInformation(tgt, config, libNames, libDirs); + // Select whether to generate an rpath for the install tree or the + // build tree. + bool linking_for_install = + relink || tgt.GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"); + bool use_install_rpath = + outputRuntime && tgt.HaveInstallTreeRPATH() && linking_for_install; + bool use_build_rpath = + outputRuntime && tgt.HaveBuildTreeRPATH() && !linking_for_install; + + // Construct the RPATH. + std::vector runtimeDirs; + if(use_install_rpath) + { + const char* install_rpath = tgt.GetProperty("INSTALL_RPATH"); + cmSystemTools::ExpandListArgument(install_rpath, runtimeDirs); + for(unsigned int i=0; i < runtimeDirs.size(); ++i) + { + runtimeDirs[i] = + this->Convert(runtimeDirs[i].c_str(), FULL, SHELL, false); + } + } + // Append the library search path flags. for(std::vector::const_iterator libDir = libDirs.begin(); libDir != libDirs.end(); ++libDir) @@ -1397,7 +1425,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout, && libDir->find("${") == std::string::npos) { linkLibs += libPathFlag; - if(outputRuntime) + if(use_build_rpath) { runtimeDirs.push_back( fullLibPath ); } @@ -1417,7 +1445,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout, fout << linkLibs; - if(outputRuntime && runtimeDirs.size()>0) + if(!runtimeDirs.empty()) { // For the runtime search directories, do a "-Wl,-rpath,a:b:c" or // a "-R a -R b -R c" type link line diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index f9dd468..9937cae 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -175,7 +175,7 @@ protected: cmTarget&target); ///! put all the libraries for a target on into the given stream - virtual void OutputLinkLibraries(std::ostream&, cmTarget&); + virtual void OutputLinkLibraries(std::ostream&, cmTarget&, bool relink); /** Compute the string to use to refer to a target in an install file. */ diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index fe1e25b..d421b4b 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1288,6 +1288,7 @@ void cmLocalUnixMakefileGenerator3 // Write special "install" target to run cmake_install.cmake script. { std::vector depends; + depends.push_back("preinstall"); std::vector commands; std::string cmd; if(m_Makefile->GetDefinition("CMake_BINARY_DIR")) @@ -1304,6 +1305,12 @@ void cmLocalUnixMakefileGenerator3 } cmd += " -P cmake_install.cmake"; commands.push_back(cmd); + this->WriteMakeRule(ruleFileStream, + "Special rule to run installation script.", + "install", depends, commands, true); + + commands.clear(); + depends.clear(); const char* noall = m_Makefile->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY"); if(!noall || cmSystemTools::IsOff(noall)) @@ -1311,9 +1318,16 @@ void cmLocalUnixMakefileGenerator3 // Drive the build before installing. depends.push_back("all"); } + else + { + // At least make sure the build system is up to date. + depends.push_back("cmake_check_build_system"); + } + commands.push_back(this->GetRecursiveMakeCall + ("CMakeFiles/Makefile2", "preinstall")); this->WriteMakeRule(ruleFileStream, - "Special rule to run installation script.", - "install", depends, commands, true); + "Prepare targets for installation.", + "preinstall", depends, commands, true); } // Write special "rebuild_cache" target to re-run cmake. diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 600cb2e..87d6feb 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -39,7 +39,12 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles() this->WriteTargetDependRules(); // write the link rules - this->WriteExecutableRule(); + this->WriteExecutableRule(false); + if(this->Target->NeedRelinkBeforeInstall()) + { + // Write rules to link an installable version of the target. + this->WriteExecutableRule(true); + } // Write the requires target. this->WriteTargetRequiresRules(); @@ -54,7 +59,7 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles() //---------------------------------------------------------------------------- -void cmMakefileExecutableTargetGenerator::WriteExecutableRule() +void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) { std::vector commands; @@ -132,6 +137,13 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule() false, false, false); } #endif + if(relink) + { + outpath = this->Makefile->GetStartOutputDirectory(); + outpath += "/CMakeFiles/CMakeRelink.dir"; + cmSystemTools::MakeDirectory(outpath.c_str()); + outpath += "/"; + } std::string targetFullPath = outpath + targetName; std::string targetFullPathReal = outpath + targetNameReal; @@ -259,7 +271,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule() // Collect up flags to link in needed libraries. cmOStringStream linklibs; - this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target); + this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink); // Construct object file lists that may be needed to expand the // rule. @@ -316,7 +328,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule() dir += "/"; dir += this->LocalGenerator->GetTargetDirectory(*this->Target); std::string buildTargetRuleName = dir; - buildTargetRuleName += "/build"; + buildTargetRuleName += relink?"/preinstall":"/build"; buildTargetRuleName = this->Convert(buildTargetRuleName.c_str(), cmLocalGenerator::HOME_OUTPUT, diff --git a/Source/cmMakefileExecutableTargetGenerator.h b/Source/cmMakefileExecutableTargetGenerator.h index a02286c..f6ffad2 100644 --- a/Source/cmMakefileExecutableTargetGenerator.h +++ b/Source/cmMakefileExecutableTargetGenerator.h @@ -27,7 +27,7 @@ public: virtual void WriteRuleFiles(); protected: - virtual void WriteExecutableRule(); + virtual void WriteExecutableRule(bool relink); }; diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index b4d5aa9..206b49d 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -46,10 +46,20 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles() this->WriteStaticLibraryRules(); break; case cmTarget::SHARED_LIBRARY: - this->WriteSharedLibraryRules(); + this->WriteSharedLibraryRules(false); + if(this->Target->NeedRelinkBeforeInstall()) + { + // Write rules to link an installable version of the target. + this->WriteSharedLibraryRules(true); + } break; case cmTarget::MODULE_LIBRARY: - this->WriteModuleLibraryRules(); + this->WriteModuleLibraryRules(false); + if(this->Target->NeedRelinkBeforeInstall()) + { + // Write rules to link an installable version of the target. + this->WriteModuleLibraryRules(true); + } break; default: // If language is not known, this is an error. @@ -82,11 +92,11 @@ void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules() std::string extraFlags; this->LocalGenerator->AppendFlags(extraFlags, this->Target->GetProperty("STATIC_LIBRARY_FLAGS")); - this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str()); + this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), false); } //---------------------------------------------------------------------------- -void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules() +void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) { const char* linkLanguage = this->Target->GetLinkerLanguage(this->GlobalGenerator); @@ -115,11 +125,11 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules() } } } - this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str()); + this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink); } //---------------------------------------------------------------------------- -void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules() +void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink) { const char* linkLanguage = this->Target->GetLinkerLanguage(this->GlobalGenerator); @@ -134,12 +144,12 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules() this->LocalGenerator->AppendFlags(extraFlags, this->Target->GetProperty("LINK_FLAGS")); this->LocalGenerator->AddConfigVariableFlags(extraFlags, "CMAKE_MODULE_LINKER_FLAGS"); // TODO: .def files should be supported here also. - this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str()); + this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink); } //---------------------------------------------------------------------------- void cmMakefileLibraryTargetGenerator::WriteLibraryRules -(const char* linkRuleVar, const char* extraFlags) +(const char* linkRuleVar, const char* extraFlags, bool relink) { // TODO: Merge the methods that call this method to avoid // code duplication. @@ -202,6 +212,13 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules outpath = this->Makefile->GetStartOutputDirectory(); outpath += "/"; } + if(relink) + { + outpath = this->Makefile->GetStartOutputDirectory(); + outpath += "/CMakeFiles/CMakeRelink.dir"; + cmSystemTools::MakeDirectory(outpath.c_str()); + outpath += "/"; + } std::string targetFullPath = outpath + targetName; std::string targetFullPathSO = outpath + targetNameSO; std::string targetFullPathReal = outpath + targetNameReal; @@ -285,9 +302,15 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules this->Makefile->GetHomeOutputDirectory()); commands.insert(commands.end(), commands1.begin(), commands1.end()); commands1.clear(); - // Add the pre-build and pre-link rules. - this->LocalGenerator->AppendCustomCommands(commands, this->Target->GetPreBuildCommands()); - this->LocalGenerator->AppendCustomCommands(commands, this->Target->GetPreLinkCommands()); + + // Add the pre-build and pre-link rules building but not when relinking. + if(!relink) + { + this->LocalGenerator + ->AppendCustomCommands(commands, this->Target->GetPreBuildCommands()); + this->LocalGenerator + ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands()); + } // Construct the main link rule. std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar); @@ -314,12 +337,16 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules commands.insert(commands.end(), commands1.begin(), commands1.end()); } - // Add the post-build rules. - this->LocalGenerator->AppendCustomCommands(commands, this->Target->GetPostBuildCommands()); + // Add the post-build rules when building but not when relinking. + if(!relink) + { + this->LocalGenerator-> + AppendCustomCommands(commands, this->Target->GetPostBuildCommands()); + } // Collect up flags to link in needed libraries. cmOStringStream linklibs; - this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target); + this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink); // Construct object file lists that may be needed to expand the // rule. @@ -381,7 +408,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules dir += "/"; dir += this->LocalGenerator->GetTargetDirectory(*this->Target); std::string buildTargetRuleName = dir; - buildTargetRuleName += "/build"; + buildTargetRuleName += relink?"/preinstall":"/build"; buildTargetRuleName = this->Convert(buildTargetRuleName.c_str(), cmLocalGenerator::HOME_OUTPUT,cmLocalGenerator::MAKEFILE); diff --git a/Source/cmMakefileLibraryTargetGenerator.h b/Source/cmMakefileLibraryTargetGenerator.h index 7c7c43d..502e35b 100644 --- a/Source/cmMakefileLibraryTargetGenerator.h +++ b/Source/cmMakefileLibraryTargetGenerator.h @@ -29,9 +29,10 @@ public: protected: void WriteStaticLibraryRules(); - void WriteSharedLibraryRules(); - void WriteModuleLibraryRules(); - void WriteLibraryRules(const char *linkRule, const char *extraFlags); + void WriteSharedLibraryRules(bool relink); + void WriteModuleLibraryRules(bool relink); + void WriteLibraryRules(const char *linkRule, const char *extraFlags, + bool relink); }; #endif diff --git a/Source/cmSetTargetPropertiesCommand.h b/Source/cmSetTargetPropertiesCommand.h index 5d5b23d..f4cb976 100644 --- a/Source/cmSetTargetPropertiesCommand.h +++ b/Source/cmSetTargetPropertiesCommand.h @@ -79,7 +79,20 @@ public: "When building or installing appropriate symlinks are created if " "the platform supports symlinks. " "The OUTPUT_NAME can be used to set an output name that is " - "used in place of the target name when creating executables. " + "used in place of the target name when creating executables.\n" + "There are a few properties used to specify RPATH rules. " + "INSTALL_RPATH is a semicolon-separated list specifying the rpath " + "to use in installed targets (for platforms that support it). " + "SKIP_BUILD_RPATH is a boolean specifying whether to skip automatic " + "generation of an rpath allowing the target to run from the " + "build tree. " + "BUILD_WITH_INSTALL_RPATH is a boolean specifying whether to link " + "the target in the build tree with the INSTALL_RPATH. This takes " + "precedence over SKIP_BUILD_RPATH and avoids the need for relinking " + "before installation. When the target is created the values of " + "the variables CMAKE_INSTALL_RPATH, CMAKE_SKIP_BUILD_RPATH, and " + "CMAKE_BUILD_WITH_INSTALL_RPATH are used to initialize these " + "properties.\n" "PROJECT_LABEL can be used to change the name of " "the target in an IDE like visual studio. VS_KEYWORD can be set " "to change the visual studio keyword, for example QT integration " diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 58a40b3..c006bf2 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -44,6 +44,17 @@ void cmTarget::SetType(TargetType type, const char* name) } } +//---------------------------------------------------------------------------- +void cmTarget::SetMakefile(cmMakefile* mf) +{ + // Set our makefile. + m_Makefile = mf; + + // Setup default property values. + this->SetPropertyDefault("INSTALL_RPATH", ""); + this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF"); + this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF"); +} void cmTarget::TraceVSDependencies(std::string projFile, cmMakefile *makefile) @@ -1309,3 +1320,93 @@ void cmTarget::GetExecutableNamesInternal(std::string& name, realName += version; } } + +//---------------------------------------------------------------------------- +void cmTarget::SetPropertyDefault(const char* property, + const char* default_value) +{ + // Compute the name of the variable holding the default value. + std::string var = "CMAKE_"; + var += property; + + if(const char* value = m_Makefile->GetDefinition(var.c_str())) + { + this->SetProperty(property, value); + } + else if(default_value) + { + this->SetProperty(property, default_value); + } +} + +//---------------------------------------------------------------------------- +bool cmTarget::HaveBuildTreeRPATH() +{ + return (!this->GetPropertyAsBool("SKIP_BUILD_RPATH") && + !m_LinkLibraries.empty()); +} + +//---------------------------------------------------------------------------- +bool cmTarget::HaveInstallTreeRPATH() +{ + const char* install_rpath = this->GetProperty("INSTALL_RPATH"); + return install_rpath && *install_rpath; +} + +//---------------------------------------------------------------------------- +bool cmTarget::NeedRelinkBeforeInstall() +{ + // Only executables and shared libraries can have an rpath and may + // need relinking. + if(m_TargetType != cmTarget::EXECUTABLE && + m_TargetType != cmTarget::SHARED_LIBRARY && + m_TargetType != cmTarget::MODULE_LIBRARY) + { + return false; + } + + // If there is no install location this target will not be installed + // and therefore does not need relinking. + if(this->GetInstallPath().empty()) + { + return false; + } + + // If skipping all rpaths completely then no relinking is needed. + if(m_Makefile->IsOn("CMAKE_SKIP_RPATH")) + { + return false; + } + + // If building with the install-tree rpath no relinking is needed. + if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) + { + return false; + } + + // Check for rpath support on this platform. + if(const char* ll = this->GetLinkerLanguage( + m_Makefile->GetLocalGenerator()->GetGlobalGenerator())) + { + std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; + flagVar += ll; + flagVar += "_FLAG"; + if(!m_Makefile->IsSet(flagVar.c_str())) + { + // There is no rpath support on this platform so nothing needs + // relinking. + return false; + } + } + else + { + // No linker language is known. This error will be reported by + // other code. + return false; + } + + // If either a build or install tree rpath is set then the rpath + // will likely change between the build tree and install tree and + // this target must be relinked. + return this->HaveBuildTreeRPATH() || this->HaveInstallTreeRPATH(); +} diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 790ab39..0f6749c 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -63,7 +63,7 @@ public: void SetInAll(bool f) { this->SetProperty("IN_ALL", (f) ?"TRUE" : "FALSE"); } ///! Set the cmMakefile that owns this target - void SetMakefile(cmMakefile *mf) { m_Makefile = mf; }; + void SetMakefile(cmMakefile *mf); cmMakefile *GetMakefile() { return m_Makefile;}; /** @@ -209,6 +209,15 @@ public: executable target. */ void GetExecutableCleanNames(std::string& name, std::string& realName, const char* config); + + /** + * Compute whether this target must be relinked before installing. + */ + bool NeedRelinkBeforeInstall(); + + bool HaveBuildTreeRPATH(); + bool HaveInstallTreeRPATH(); + private: /** * A list of direct dependencies. Use in conjunction with DependencyMap. @@ -281,7 +290,10 @@ private: // update the value of the LOCATION var void UpdateLocation(); - + + // Use a makefile variable to set a default for the given property. + // If the variable is not defined use the given default instead. + void SetPropertyDefault(const char* property, const char* default_value); private: std::string m_Name; std::vector m_PreBuildCommands; diff --git a/Tests/SimpleInstall/CMakeLists.txt b/Tests/SimpleInstall/CMakeLists.txt index b238b87..4f64662 100644 --- a/Tests/SimpleInstall/CMakeLists.txt +++ b/Tests/SimpleInstall/CMakeLists.txt @@ -8,6 +8,9 @@ SET(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}") # avoids infinite loops when the post-build rule below installs. SET(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY 1) +# Make sure the test executable can run from the install tree. +SET(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) + SET(CMAKE_DEBUG_POSTFIX "_test_debug_postfix") SET(EXTRA_INSTALL_FLAGS) diff --git a/Tests/SimpleInstallS2/CMakeLists.txt b/Tests/SimpleInstallS2/CMakeLists.txt index b238b87..4f64662 100644 --- a/Tests/SimpleInstallS2/CMakeLists.txt +++ b/Tests/SimpleInstallS2/CMakeLists.txt @@ -8,6 +8,9 @@ SET(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}") # avoids infinite loops when the post-build rule below installs. SET(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY 1) +# Make sure the test executable can run from the install tree. +SET(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) + SET(CMAKE_DEBUG_POSTFIX "_test_debug_postfix") SET(EXTRA_INSTALL_FLAGS) -- cgit v0.12