From 92ff60b6a64abfac46c91c7f82b400081b6f7832 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 9 Mar 2007 15:14:27 -0500 Subject: ENH: Added target properties ARCHIVE_OUTPUT_DIRECTORY, LIBRARY_OUTPUT_DIRECTORY, and RUNTIME_OUTPUT_DIRECTORY. If set these override EXECUTABLE_OUTPUT_PATH and LIBRARY_OUTPUT_PATH for a specific target. They can be used to distribute target files in the build tree with the same granularity that the INSTALL command provides for the install tree. This addresses bug#2240 and bug#4210. --- Source/cmTarget.cxx | 162 +++++++++++++++++++++++++++++++++++++++++++--------- Source/cmTarget.h | 1 + 2 files changed, 135 insertions(+), 28 deletions(-) diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 47e8a90..5f110d3 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -265,6 +265,44 @@ void cmTarget::DefineProperties(cmake *cm) "converts the source list for the target into a list of full " "paths to object names that will be produced by the target."); +#define CM_TARGET_FILE_TYPES_DOC \ + "There are three kinds of target files that may be built: " \ + "archive, library, and runtime. " \ + "Executables are always treated as runtime targets. " \ + "Static libraries are always treated as archive targets. " \ + "Module libraries are always treated as library targets. " \ + "For non-DLL platforms shared libraries are treated as library " \ + "targets. " \ + "For DLL platforms the DLL part of a shared library is treated as " \ + "a runtime target and the corresponding import library is treated as " \ + "an archive target. " \ + "All Windows-based systems including Cygwin are DLL platforms." + + cm->DefineProperty + ("ARCHIVE_OUTPUT_DIRECTORY", cmProperty::TARGET, + "Output directory in which to build ARCHIVE target files.", + "This property specifies the directory into which archive target files " + "should be built. " + CM_TARGET_FILE_TYPES_DOC " " + "This property is initialized by the value of the variable " + "CMAKE_ARCHIVE_OUTPUT_DIRECTORY if it is set when a target is created."); + cm->DefineProperty + ("LIBRARY_OUTPUT_DIRECTORY", cmProperty::TARGET, + "Output directory in which to build LIBRARY target files.", + "This property specifies the directory into which library target files " + "should be built. " + CM_TARGET_FILE_TYPES_DOC " " + "This property is initialized by the value of the variable " + "CMAKE_LIBRARY_OUTPUT_DIRECTORY if it is set when a target is created."); + cm->DefineProperty + ("RUNTIME_OUTPUT_DIRECTORY", cmProperty::TARGET, + "Output directory in which to build RUNTIME target files.", + "This property specifies the directory into which runtime target files " + "should be built. " + CM_TARGET_FILE_TYPES_DOC " " + "This property is initialized by the value of the variable " + "CMAKE_RUNTIME_OUTPUT_DIRECTORY if it is set when a target is created."); + // define some properties without documentation cm->DefineProperty("DEBUG_OUTPUT_NAME", cmProperty::TARGET,0,0); cm->DefineProperty("RELEASE_OUTPUT_NAME", cmProperty::TARGET,0,0); @@ -302,6 +340,9 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF"); this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF"); this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF"); + this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", 0); + this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", 0); + this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", 0); // Collect the set of configuration types. std::vector configNames; @@ -639,6 +680,10 @@ const std::vector& cmTarget::GetLinkDirectories() // Make sure the complete set of link directories has been computed. if(!this->LinkDirectoriesComputed) { + // Check whether we should use an import library for linking a target. + bool implib = + this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX") != 0; + // Compute the full set of link directories including the // locations of targets that have been linked in. Start with the // link directories given explicitly. @@ -661,7 +706,7 @@ const std::vector& cmTarget::GetLinkDirectories() // Add the directory only if it is not already present. This // is an N^2 algorithm for adding the directories, but N // should not get very big. - const char* libpath = tgt->GetDirectory(0, true); + const char* libpath = tgt->GetDirectory(0, implib); if(std::find(this->LinkDirectories.begin(), this->LinkDirectories.end(), libpath) == this->LinkDirectories.end()) @@ -1199,6 +1244,11 @@ void cmTarget::ComputeObjectFiles() const char *cmTarget::GetProperty(const char* prop, cmProperty::ScopeType scope) { + if(!prop) + { + return 0; + } + // watch for special "computed" properties that are dependent on other // properties or variables, always recompute them if (!strcmp(prop,"LOCATION")) @@ -1943,54 +1993,110 @@ const char* cmTarget::GetOutputDir(bool implib) implib = false; } - // For now the import library is always in the same directory as the DLL. - static_cast(implib); + // Sanity check. Only generators on platforms supporting import + // libraries should be asking for the import library output + // directory. + if(implib && + !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) + { + abort(); + } + + // Select whether we are constructing the directory for the main + // target or the import library. + std::string& out = implib? this->OutputDirImplib : this->OutputDir; - if(this->OutputDir.empty()) + if(out.empty()) { - // Lookup the output path for this target type. - if(this->GetType() == cmTarget::EXECUTABLE) + // Look for a target property defining the target output directory + // based on the target type. + const char* propertyName = 0; + switch(this->GetType()) + { + case cmTarget::SHARED_LIBRARY: + { + // For non-DLL platforms shared libraries are treated as + // library targets. For DLL platforms the DLL part of a + // shared library is treated as a runtime target and the + // corresponding import library is treated as an archive + // target. + + // Check whether this is a DLL platform. + bool dll_platform = (this->Makefile->IsOn("WIN32") || + this->Makefile->IsOn("CYGWIN") || + this->Makefile->IsOn("MINGW")); + if(dll_platform) + { + if(implib) + { + propertyName = "ARCHIVE_OUTPUT_DIRECTORY"; + } + else + { + propertyName = "RUNTIME_OUTPUT_DIRECTORY"; + } + } + else + { + propertyName = "LIBRARY_OUTPUT_DIRECTORY"; + } + } break; + case cmTarget::STATIC_LIBRARY: + { + // Static libraries are always treated as archive targets. + propertyName = "ARCHIVE_OUTPUT_DIRECTORY"; + } break; + case cmTarget::MODULE_LIBRARY: + { + // Module libraries are always treated as library targets. + propertyName = "LIBRARY_OUTPUT_DIRECTORY"; + } break; + case cmTarget::EXECUTABLE: + { + // Executables are always treated as runtime targets. + propertyName = "RUNTIME_OUTPUT_DIRECTORY"; + } break; + default: break; + } + + // Select an output directory. + if(const char* outdir = this->GetProperty(propertyName)) { - this->OutputDir = - this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH"); + // Use the user-specified output directory. + out = outdir; + } + else if(this->GetType() == cmTarget::EXECUTABLE) + { + // Lookup the output path for executables. + out = this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH"); } else if(this->GetType() == cmTarget::STATIC_LIBRARY || this->GetType() == cmTarget::SHARED_LIBRARY || this->GetType() == cmTarget::MODULE_LIBRARY) { - this->OutputDir = - this->Makefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH"); + // Lookup the output path for libraries. + out = this->Makefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH"); } - if(this->OutputDir.empty()) + if(out.empty()) { - this->OutputDir = "."; + // Default to the current output directory. + out = "."; } // Convert the output path to a full path in case it is // specified as a relative path. Treat a relative path as // relative to the current output directory for this makefile. - this->OutputDir = + out = cmSystemTools::CollapseFullPath - (this->OutputDir.c_str(), this->Makefile->GetStartOutputDirectory()); + (out.c_str(), this->Makefile->GetStartOutputDirectory()); // Make sure the output path exists on disk. - if(!cmSystemTools::MakeDirectory(this->OutputDir.c_str())) + if(!cmSystemTools::MakeDirectory(out.c_str())) { cmSystemTools::Error("Error failed to create output directory:", - this->OutputDir.c_str()); + out.c_str()); } - - // This came from cmLocalUnixMakefileGenerator3::FormatOutputPath. - // Where should it go? Is it still needed? I do not think so - // because target full paths are split into -Ldir -llib - // automatically. - // - // Add this as a link directory automatically. - // this->Makefile->AddLinkDirectory(path.c_str()); - // - // Should it be this? - // this->AddLinkDirectory(this->OutputDir.c_str()); } - return this->OutputDir.c_str(); + return out.c_str(); } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index d5b5474..665c97b 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -361,6 +361,7 @@ private: std::string InstallPath; std::string RuntimeInstallPath; std::string OutputDir; + std::string OutputDirImplib; std::string Directory; std::string Location; std::set Utilities; -- cgit v0.12