From 586a9427d3dd8b4a99f7a3d545814f8b9bf42453 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 24 Feb 2006 13:13:14 -0500 Subject: ENH: Created target property INSTALL_NAME_DIR initalized by CMAKE_INSTALL_NAME_DIR specifying the directory portion of the OSX install_name field in shared libraries. This is the OSX equivalent of RPATH. --- Modules/Platform/Darwin.cmake | 36 ++---- Source/cmGlobalXCodeGenerator.cxx | 102 +++++++++++++++- Source/cmGlobalXCodeGenerator.h | 5 + Source/cmInstallTargetGenerator.cxx | 173 ++++++++++++++++++++++++++-- Source/cmInstallTargetGenerator.h | 8 +- Source/cmLocalGenerator.cxx | 7 ++ Source/cmLocalGenerator.h | 2 + Source/cmMakefileLibraryTargetGenerator.cxx | 41 ++++++- Source/cmSetTargetPropertiesCommand.h | 11 +- Source/cmTarget.cxx | 60 +++++++++- Source/cmTarget.h | 13 ++- Tests/SimpleInstall/CMakeLists.txt | 3 + Tests/SimpleInstallS2/CMakeLists.txt | 3 + 13 files changed, 409 insertions(+), 55 deletions(-) diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake index f6e5946..46374cf 100644 --- a/Modules/Platform/Darwin.cmake +++ b/Modules/Platform/Darwin.cmake @@ -4,8 +4,11 @@ SET(CMAKE_SHARED_MODULE_PREFIX "lib") SET(CMAKE_SHARED_MODULE_SUFFIX ".so") SET(CMAKE_MODULE_EXISTS 1) SET(CMAKE_DL_LIBS "") -SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib") -SET(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle") +SET(CMAKE_C_LINK_FLAGS "-headerpad_max_install_names") +SET(CMAKE_CXX_LINK_FLAGS "-headerpad_max_install_names") +SET(CMAKE_PLATFORM_HAS_INSTALLNAME 1) +SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names") +SET(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names") SET(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a") IF("${CMAKE_BACKWARDS_COMPATIBILITY}" MATCHES "^1\\.[0-6]$") @@ -14,32 +17,17 @@ IF("${CMAKE_BACKWARDS_COMPATIBILITY}" MATCHES "^1\\.[0-6]$") ENDIF("${CMAKE_BACKWARDS_COMPATIBILITY}" MATCHES "^1\\.[0-6]$") IF(NOT XCODE) -# Enable shared library versioning. + # Enable shared library versioning. This flag is not actually referenced + # but the fact that the setting exists will cause the generators to support + # soname computation. SET(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-install_name") SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-install_name") ENDIF(NOT XCODE) -# OSX does not really implement an rpath, but it does allow a path to -# be specified in the soname field of a dylib. -IF(CMAKE_SKIP_RPATH) - # No rpath requested. Just use the soname directly. - SET(CMAKE_C_CREATE_SHARED_LIBRARY - " -o ") - SET(CMAKE_CXX_CREATE_SHARED_LIBRARY - " -o ") -ELSE(CMAKE_SKIP_RPATH) - # Support for rpath is requested. Approximate it by putting the - # full path to the library in the soname field. Then when executables - # link the library they will copy this full path as the name to use - # to find the library. We can get the directory containing the library - # by using the dirname of the . It may be a relative path - # so we use a "cd ...;pwd" trick to convert it to a full path at - # build time. - SET(CMAKE_C_CREATE_SHARED_LIBRARY - " -o \"`cd \\`dirname \\`\;pwd`/\" ") - SET(CMAKE_CXX_CREATE_SHARED_LIBRARY - " -o \"`cd \\`dirname \\`\;pwd`/\" ") -ENDIF(CMAKE_SKIP_RPATH) +SET(CMAKE_C_CREATE_SHARED_LIBRARY + " -o -install_name ") +SET(CMAKE_CXX_CREATE_SHARED_LIBRARY + " -o -install_name ") SET(CMAKE_CXX_CREATE_SHARED_MODULE " -o ") diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 273c98c..d15e53b 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1145,13 +1145,30 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, outflag += "\\\""; extraLinkOptions += " "; extraLinkOptions += outflag; + + // Add the flags to create an executable. + std::string createFlags = + this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", ""); + if(!createFlags.empty()) + { + extraLinkOptions += " "; + extraLinkOptions += createFlags; + } } else { fileType = "compiled.mach-o.dylib"; productType = "com.apple.product-type.library.dynamic"; - extraLinkOptions += " -bundle"; + // Add the flags to create a module. + std::string createFlags = + this->LookupFlags("CMAKE_SHARED_MODULE_CREATE_", lang, "_FLAGS", + "-bundle"); + if(!createFlags.empty()) + { + extraLinkOptions += " "; + extraLinkOptions += createFlags; + } } break; } @@ -1166,13 +1183,31 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, this->CreateString("1")); buildSettings->AddAttribute("DYLIB_CURRENT_VERSION", this->CreateString("1")); - extraLinkOptions += " -dynamiclib"; + + // Add the flags to create a shared library. + std::string createFlags = + this->LookupFlags("CMAKE_SHARED_LIBRARY_CREATE_", lang, "_FLAGS", + "-dynamiclib"); + if(!createFlags.empty()) + { + extraLinkOptions += " "; + extraLinkOptions += createFlags; + } break; } case cmTarget::EXECUTABLE: { fileType = "compiled.mach-o.executable"; + // Add the flags to create an executable. + std::string createFlags = + this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", ""); + if(!createFlags.empty()) + { + extraLinkOptions += " "; + extraLinkOptions += createFlags; + } + // Handle bundles and normal executables separately. if(target.GetPropertyAsBool("MACOSX_BUNDLE")) { @@ -1284,8 +1319,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, this->CreateString(debugStr)); buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL", this->CreateString(optLevel)); - buildSettings->AddAttribute("INSTALL_PATH", - this->CreateString("")); buildSettings->AddAttribute("OPTIMIZATION_CFLAGS", this->CreateString(oflagc.c_str())); if(lang && strcmp(lang, "CXX") == 0) @@ -1307,9 +1340,45 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, buildSettings->AddAttribute("OTHER_CFLAGS", this->CreateString(flags.c_str())); } + + // Create the INSTALL_PATH attribute. + std::string install_name_dir; + if(target.GetType() == cmTarget::SHARED_LIBRARY) + { + // Select whether to generate an install_name directory for the + // install tree or the build tree. + if(target.GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) + { + install_name_dir = + target.GetInstallNameDirForInstallTree(configName); + } + else + { + install_name_dir = + target.GetInstallNameDirForBuildTree(configName); + } + + if(install_name_dir.empty()) + { + // Xcode will not pass the -install_name option at all if INSTALL_PATH + // is not given or is empty. We must explicitly put the flag in the + // link flags to create an install_name with just the library soname. + extraLinkOptions += " -install_name "; + extraLinkOptions += productName; + } + else + { + // Convert to a path for the native build tool. + cmSystemTools::ConvertToUnixSlashes(install_name_dir); + install_name_dir = + this->XCodeEscapePath(install_name_dir.c_str()); + } + } + buildSettings->AddAttribute("INSTALL_PATH", + this->CreateString(install_name_dir.c_str())); + buildSettings->AddAttribute("OTHER_LDFLAGS", this->CreateString(extraLinkOptions.c_str())); - buildSettings->AddAttribute("OTHER_REZFLAGS", this->CreateString("")); buildSettings->AddAttribute("SECTORDER_FLAGS", @@ -2317,3 +2386,26 @@ cmGlobalXCodeGenerator } } } + +//---------------------------------------------------------------------------- +std::string cmGlobalXCodeGenerator::LookupFlags(const char* varNamePrefix, + const char* varNameLang, + const char* varNameSuffix, + const char* default_flags) +{ + if(varNameLang) + { + std::string varName = varNamePrefix; + varName += varNameLang; + varName += varNameSuffix; + if(const char* varValue = + m_CurrentMakefile->GetDefinition(varName.c_str())) + { + if(*varValue) + { + return varValue; + } + } + } + return default_flags; +} diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 7d49b34..0e6f65f 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -142,6 +142,11 @@ private: cmTarget& cmtarget, const std::vector&); void CreateReRunCMakeFile(cmLocalGenerator* root); + + std::string LookupFlags(const char* varNamePrefix, + const char* varNameLang, + const char* varNameSuffix, + const char* default_flags); protected: int m_XcodeVersion; diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 243ba63..62f0504 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -52,10 +52,11 @@ void cmInstallTargetGenerator::GenerateScript(std::ostream& os) } // Write variable settings to do per-configuration references. - this->PrepareInstallReference(os); + this->PrepareScriptReference(os, this->Target, "BUILD", true, false); // Create the per-configuration reference. - std::string fromName = this->GetInstallReference(); + std::string fromName = this->GetScriptReference(this->Target, "BUILD", + false); std::string fromFile = fromDir; fromFile += fromName; @@ -150,12 +151,22 @@ void cmInstallTargetGenerator::GenerateScript(std::ostream& os) // Write code to install the target file. this->AddInstallRule(os, this->Destination.c_str(), type, fromFile.c_str(), this->ImportLibrary, properties); + + // Fix the install_name settings in installed binaries. + if(type == cmTarget::SHARED_LIBRARY || + type == cmTarget::MODULE_LIBRARY || + type == cmTarget::EXECUTABLE) + { + this->AddInstallNamePatchRule(os); + } } //---------------------------------------------------------------------------- void cmInstallTargetGenerator -::PrepareInstallReference(std::ostream& os) +::PrepareScriptReference(std::ostream& os, cmTarget* target, + const char* place, bool useConfigDir, + bool useSOName) { // If the target name may vary with the configuration type then // store all possible names ahead of time in variables. @@ -164,42 +175,180 @@ cmInstallTargetGenerator this->ConfigurationTypes->begin(); i != this->ConfigurationTypes->end(); ++i) { - // Start with the configuration's subdirectory. + // Initialize the name. fname = ""; - this->Target->GetMakefile()->GetLocalGenerator()->GetGlobalGenerator()-> - AppendDirectoryForConfig(i->c_str(), fname); + + if(useConfigDir) + { + // Start with the configuration's subdirectory. + target->GetMakefile()->GetLocalGenerator()->GetGlobalGenerator()-> + AppendDirectoryForConfig(i->c_str(), fname); + } + + // Compute the name of the library. + std::string targetName; + std::string targetNameSO; + std::string targetNameReal; + std::string targetNameImport; + target->GetLibraryNames(targetName, targetNameSO, targetNameReal, + targetNameImport, i->c_str()); + if(this->ImportLibrary) + { + // Use the import library name. + fname += targetNameImport; + } + else if(useSOName) + { + // Use the soname. + fname += targetNameSO; + } + else + { + // Use the canonical name. + fname += targetName; + } // Set a variable with the target name for this configuration. - fname += this->Target->GetFullName(i->c_str(), this->ImportLibrary); - os << "SET(" << this->Target->GetName() + os << "SET(" << target->GetName() << "_" << place << (this->ImportLibrary? "_IMPNAME_" : "_NAME_") << *i << " \"" << fname << "\")\n"; } } //---------------------------------------------------------------------------- -std::string cmInstallTargetGenerator::GetInstallReference() +std::string cmInstallTargetGenerator::GetScriptReference(cmTarget* target, + const char* place, + bool useSOName) { if(this->ConfigurationTypes->empty()) { // Reference the target by its one configuration name. - return this->Target->GetFullName(this->ConfigurationName, - this->ImportLibrary); + std::string targetName; + std::string targetNameSO; + std::string targetNameReal; + std::string targetNameImport; + target->GetLibraryNames(targetName, targetNameSO, targetNameReal, + targetNameImport, this->ConfigurationName); + if(this->ImportLibrary) + { + // Use the import library name. + return targetNameImport; + } + else if(useSOName) + { + // Use the soname. + return targetNameSO; + } + else + { + // Use the canonical name. + return targetName; + } } else { // Reference the target using the per-configuration variable. std::string ref = "${"; - ref += this->Target->GetName(); + ref += target->GetName(); if(this->ImportLibrary) { + ref += "_"; + ref += place; ref += "_IMPNAME_"; } else { + ref += "_"; + ref += place; ref += "_NAME_"; } ref += "${CMAKE_INSTALL_CONFIG_NAME}}"; return ref; } } + +//---------------------------------------------------------------------------- +void cmInstallTargetGenerator::AddInstallNamePatchRule(std::ostream& os) +{ + // Build a map of build-tree install_name to install-tree install_name for + // shared libraries linked to this target. + std::map install_name_remap; + cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED; + const char* config = this->ConfigurationName; + if(config && cmSystemTools::UpperCase(config) == "DEBUG") + { + linkType = cmTarget::DEBUG; + } + // TODO: Merge with ComputeLinkInformation. + const cmTarget::LinkLibraries& inLibs = this->Target->GetLinkLibraries(); + for(cmTarget::LinkLibraries::const_iterator j = inLibs.begin(); + j != inLibs.end(); ++j) + { + std::string lib = j->first; + if((this->Target->GetType() == cmTarget::EXECUTABLE || + lib != this->Target->GetName()) && + (j->second == cmTarget::GENERAL || j->second == linkType)) + { + if(cmTarget* tgt = this->Target->GetMakefile()->GetLocalGenerator()->GetGlobalGenerator()->FindTarget(0, lib.c_str())) + { + if(tgt->GetType() == cmTarget::SHARED_LIBRARY) + { + // If the build tree and install tree use different path components + // of the install_name field then we need to create a mapping to be + // applied after installation. + std::string for_build = tgt->GetInstallNameDirForBuildTree(config); + std::string for_install = tgt->GetInstallNameDirForInstallTree(config); + if(for_build != for_install) + { + // Map from the build-tree install_name. + this->PrepareScriptReference(os, tgt, "REMAP_FROM", + !for_build.empty(), true); + for_build += this->GetScriptReference(tgt, "REMAP_FROM", true); + + // Map to the install-tree install_name. + this->PrepareScriptReference(os, tgt, "REMAP_TO", + false, true); + for_install += this->GetScriptReference(tgt, "REMAP_TO", true); + + // Store the mapping entry. + install_name_remap[for_build] = for_install; + } + } + } + } + } + + // Edit the install_name of the target itself if necessary. + this->PrepareScriptReference(os, this->Target, "REMAPPED", false, true); + std::string new_id; + if(this->Target->GetType() == cmTarget::SHARED_LIBRARY) + { + std::string for_build = this->Target->GetInstallNameDirForBuildTree(config); + std::string for_install = this->Target->GetInstallNameDirForInstallTree(config); + if(for_build != for_install) + { + // Prepare to refer to the install-tree install_name. + new_id = for_install; + new_id += this->GetScriptReference(this->Target, "REMAPPED", true); + } + } + + // Write a rule to run install_name_tool to set the install-tree + // install_name value and references. + if(!new_id.empty() || !install_name_remap.empty()) + { + os << "EXECUTE_PROCESS(COMMAND install_name_tool"; + if(!new_id.empty()) + { + os << "\n -id \"" << new_id << "\""; + } + for(std::map::const_iterator + i = install_name_remap.begin(); + i != install_name_remap.end(); ++i) + { + os << "\n -change \"" << i->first << "\" \"" << i->second << "\""; + } + os << "\n \"" << this->Destination.c_str() << "/" + << this->GetScriptReference(this->Target, "REMAPPED", true) << "\")\n"; + } +} diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index 6e13ac8..ac7058a 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -33,8 +33,12 @@ public: protected: virtual void GenerateScript(std::ostream& os); - void PrepareInstallReference(std::ostream& os); - std::string GetInstallReference(); + void PrepareScriptReference(std::ostream& os, cmTarget* target, + const char* place, bool useConfigDir, + bool useSOName); + std::string GetScriptReference(cmTarget* target, const char* place, + bool useSOName); + void AddInstallNamePatchRule(std::ostream& os); cmTarget* Target; std::string Destination; bool ImportLibrary; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 1f6a596..ab2d31d 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -643,6 +643,13 @@ cmLocalGenerator::ExpandRuleVariable(std::string const& variable, return ""; } } + if(replaceValues.TargetInstallNameDir) + { + if(variable == "TARGET_INSTALLNAME_DIR") + { + return replaceValues.TargetInstallNameDir; + } + } if(replaceValues.LinkLibraries) { if(variable == "LINK_LIBRARIES") diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 7260513..d28917a 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -182,6 +182,7 @@ public: this->Flags= 0; this->ObjectsQuoted= 0; this->TargetSOName= 0; + this->TargetInstallNameDir = 0; this->LinkFlags= 0; } const char* Language; @@ -193,6 +194,7 @@ public: const char* Flags; const char* ObjectsQuoted; const char* TargetSOName; + const char* TargetInstallNameDir; const char* LinkFlags; }; diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index d8bc80e..a5b6154 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -392,7 +392,46 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules vars.ObjectsQuoted = buildObjs.c_str(); vars.TargetSOName= targetNameSO.c_str(); vars.LinkFlags = linkFlags.c_str(); - + + // Compute the directory portion of the install_name setting. + std::string install_name_dir; + if(this->Target->GetType() == cmTarget::SHARED_LIBRARY) + { + // Select whether to generate an install_name directory for the + // install tree or the build tree. + const char* config = this->LocalGenerator->m_ConfigurationName.c_str(); + if(this->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) + { + install_name_dir = + this->Target->GetInstallNameDirForInstallTree(config); + } + else + { + install_name_dir = + this->Target->GetInstallNameDirForBuildTree(config); + } + + // Set the rule variable replacement value. + if(install_name_dir.empty()) + { + vars.TargetInstallNameDir = ""; + } + else + { + // Convert to a path for the native build tool. + install_name_dir = + this->LocalGenerator->Convert(install_name_dir.c_str(), + cmLocalGenerator::FULL, + cmLocalGenerator::SHELL, false); + + // The Convert method seems to strip trailing slashes, which should + // probably be fixed. Since the only platform supporting install_name + // right now uses forward slashes just add one. + install_name_dir += "/"; + vars.TargetInstallNameDir = install_name_dir.c_str(); + } + } + // Expand placeholders in the commands. this->LocalGenerator->m_TargetImplib = targetOutPathImport; for(std::vector::iterator i = commands.begin(); diff --git a/Source/cmSetTargetPropertiesCommand.h b/Source/cmSetTargetPropertiesCommand.h index e3afd76..2bb9a81 100644 --- a/Source/cmSetTargetPropertiesCommand.h +++ b/Source/cmSetTargetPropertiesCommand.h @@ -95,10 +95,13 @@ public: "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" + "before installation. INSTALL_NAME_DIR is a string specifying the " + "directory portion of the \"install_name\" field of shared libraries " + "on Mac OSX to use in the installed targets. " + "When the target is created the values of " + "the variables CMAKE_INSTALL_RPATH, CMAKE_SKIP_BUILD_RPATH, " + "CMAKE_BUILD_WITH_INSTALL_RPATH, and CMAKE_INSTALL_NAME_DIR " + "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 e15dcdd..68788fa 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -52,6 +52,7 @@ void cmTarget::SetMakefile(cmMakefile* mf) m_Makefile = mf; // Setup default property values. + this->SetPropertyDefault("INSTALL_NAME_DIR", ""); this->SetPropertyDefault("INSTALL_RPATH", ""); this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF"); this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF"); @@ -775,7 +776,7 @@ void cmTarget::SetProperty(const char* prop, const char* value) m_Properties[prop] = value; } -const char* cmTarget::GetDirectory() +const char* cmTarget::GetDirectory(const char* config) { switch( this->GetType() ) { @@ -794,6 +795,13 @@ const char* cmTarget::GetDirectory() { m_Directory = m_Makefile->GetStartOutputDirectory(); } + if(config) + { + // Add the configuration's subdirectory. + m_Directory += "/"; + m_Makefile->GetLocalGenerator()->GetGlobalGenerator()-> + AppendDirectoryForConfig(config, m_Directory); + } return m_Directory.c_str(); } @@ -1069,13 +1077,9 @@ void cmTarget::GetFullName(std::string& prefix, std::string& base, std::string cmTarget::GetFullPath(const char* config, bool implib) { // Start with the output directory for the target. - std::string fpath = this->GetDirectory(); + std::string fpath = this->GetDirectory(config); fpath += "/"; - // Add the configuration's subdirectory. - m_Makefile->GetLocalGenerator()->GetGlobalGenerator()-> - AppendDirectoryForConfig(config, fpath); - // Add the full name of the target. fpath += this->GetFullName(config, implib); return fpath; @@ -1440,3 +1444,47 @@ bool cmTarget::NeedRelinkBeforeInstall() // this target must be relinked. return this->HaveBuildTreeRPATH() || this->HaveInstallTreeRPATH(); } + +//---------------------------------------------------------------------------- +std::string cmTarget::GetInstallNameDirForBuildTree(const char* config) +{ + // If building directly for installation then the build tree install_name + // is the same as the install tree. + if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) + { + return GetInstallNameDirForInstallTree(config); + } + + // Use the build tree directory for the target. + if(m_Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME") && + !m_Makefile->IsOn("CMAKE_SKIP_RPATH") && + !this->GetPropertyAsBool("SKIP_BUILD_RPATH")) + { + std::string dir = this->GetDirectory(config); + dir += "/"; + return dir; + } + else + { + return ""; + } +} + +//---------------------------------------------------------------------------- +std::string cmTarget::GetInstallNameDirForInstallTree(const char*) +{ + // Lookup the target property. + const char* install_name_dir = this->GetProperty("INSTALL_NAME_DIR"); + if(m_Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME") && + !m_Makefile->IsOn("CMAKE_SKIP_RPATH") && + install_name_dir && *install_name_dir) + { + std::string dir = install_name_dir; + dir += "/"; + return dir; + } + else + { + return ""; + } +} diff --git a/Source/cmTarget.h b/Source/cmTarget.h index eb455fa..bb4140b 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -157,7 +157,15 @@ public: const char *GetProperty(const char *prop); bool GetPropertyAsBool(const char *prop); - const char* GetDirectory(); + /** Get the directory in which this target will be built. If the + configuration name is given then the generator will add its + subdirectory for that configuration. Otherwise just the canonical + output directory is given. */ + const char* GetDirectory(const char* config = 0); + + /** Get the location of the target in the build tree for the given + configuration. This location is suitable for use as the LOCATION + target property. */ const char* GetLocation(const char* config); /** @@ -222,6 +230,9 @@ public: bool HaveBuildTreeRPATH(); bool HaveInstallTreeRPATH(); + std::string GetInstallNameDirForBuildTree(const char* config); + std::string GetInstallNameDirForInstallTree(const char* config); + private: /** * A list of direct dependencies. Use in conjunction with DependencyMap. diff --git a/Tests/SimpleInstall/CMakeLists.txt b/Tests/SimpleInstall/CMakeLists.txt index a12fdcd..c712978 100644 --- a/Tests/SimpleInstall/CMakeLists.txt +++ b/Tests/SimpleInstall/CMakeLists.txt @@ -9,6 +9,9 @@ SET(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}") # tree. SET(CMAKE_SKIP_BUILD_RPATH 1) +# Make sure the executable can run from the install tree. +SET(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib) + # Skip the dependency that causes a build when installing. This # avoids infinite loops when the post-build rule below installs. SET(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY 1) diff --git a/Tests/SimpleInstallS2/CMakeLists.txt b/Tests/SimpleInstallS2/CMakeLists.txt index a12fdcd..c712978 100644 --- a/Tests/SimpleInstallS2/CMakeLists.txt +++ b/Tests/SimpleInstallS2/CMakeLists.txt @@ -9,6 +9,9 @@ SET(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}") # tree. SET(CMAKE_SKIP_BUILD_RPATH 1) +# Make sure the executable can run from the install tree. +SET(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib) + # Skip the dependency that causes a build when installing. This # avoids infinite loops when the post-build rule below installs. SET(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY 1) -- cgit v0.12