diff options
Diffstat (limited to 'Source')
42 files changed, 1324 insertions, 418 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e99da49..163dab3 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -16,6 +16,8 @@ if(NOT CMake_DEFAULT_RECURSION_LIMIT) set(CMake_DEFAULT_RECURSION_LIMIT 100) elseif(MINGW OR MSYS) set(CMake_DEFAULT_RECURSION_LIMIT 400) + elseif(WIN32 AND CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64") + set(CMake_DEFAULT_RECURSION_LIMIT 400) elseif(WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM") set(CMake_DEFAULT_RECURSION_LIMIT 600) else() diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 616c7e8..73bda5f 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 26) -set(CMake_VERSION_PATCH 20230301) +set(CMake_VERSION_PATCH 20230314) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake index 73e7ef2..f5b7587 100644 --- a/Source/Checks/cm_cxx_features.cmake +++ b/Source/Checks/cm_cxx_features.cmake @@ -38,6 +38,8 @@ function(cm_check_cxx_feature name) string(REGEX REPLACE " +0 Warning\\(s\\)" "" check_output "${check_output}") # Filter out MSBuild output that looks like a warning. string(REGEX REPLACE "[^\n]*warning MSB[0-9][0-9][0-9][0-9][^\n]*" "" check_output "${check_output}") + # Filter out MSVC output that looks like a command-line warning. + string(REGEX REPLACE "[^\n]*warning D[0-9][0-9][0-9][0-9][^\n]*" "" check_output "${check_output}") # Filter out warnings caused by user flags. string(REGEX REPLACE "[^\n]*warning:[^\n]*-Winvalid-command-line-argument[^\n]*" "" check_output "${check_output}") # Filter out warnings caused by local configuration. diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 1705763..5601bf2 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -25,7 +25,6 @@ #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" -#include "cmTarget.h" #include "cmValue.h" cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt) @@ -248,7 +247,7 @@ std::string cmCommonTargetGenerator::GetManifests(const std::string& config) std::string cmCommonTargetGenerator::GetAIXExports(std::string const&) { std::string aixExports; - if (this->GeneratorTarget->Target->IsAIX()) { + if (this->GeneratorTarget->IsAIX()) { if (cmValue exportAll = this->GeneratorTarget->GetProperty("AIX_EXPORT_ALL_SYMBOLS")) { if (cmIsOff(*exportAll)) { diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index ff688a4..a93477b 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -1157,7 +1157,7 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry) // Pass the full path to the target file. BT<std::string> lib = BT<std::string>( tgt->GetFullPath(config, artifact, true), item.Backtrace); - if (tgt->Target->IsAIX() && cmHasLiteralSuffix(lib.Value, "-NOTFOUND") && + if (tgt->IsAIX() && cmHasLiteralSuffix(lib.Value, "-NOTFOUND") && artifact == cmStateEnums::ImportLibraryArtifact) { // This is an imported executable on AIX that has ENABLE_EXPORTS // but not IMPORTED_IMPLIB. CMake used to produce and accept such @@ -1185,7 +1185,7 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry) if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s) || (entry.Feature == DEFAULT && cmSystemTools::IsPathToFramework(item.Value) && - this->Makefile->IsOn("APPLE"))) { + this->Target->IsApple())) { // This is a framework. this->AddFrameworkItem(entry); } else if (cmSystemTools::FileIsFullPath(item.Value)) { @@ -1563,7 +1563,7 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry) this->OldLinkDirItems.push_back(item.Value); } - if (target->IsFrameworkOnApple() && !this->GlobalGenerator->IsXcode()) { + if (target->IsFrameworkOnApple()) { // Add the framework directory and the framework item itself auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath( item.Value, cmGlobalGenerator::FrameworkFormat::Extended); @@ -1579,26 +1579,32 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry) // Add the directory portion to the framework search path. this->AddFrameworkPath(fwDescriptor->Directory); } - if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) { - this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes, - target, - this->FindLibraryFeature(entry.Feature)); - } else { + + if (this->GlobalGenerator->IsXcode()) { this->Items.emplace_back( item, ItemIsPath::Yes, target, - this->FindLibraryFeature( - entry.Feature == DEFAULT ? "__CMAKE_LINK_LIBRARY" : entry.Feature)); + this->FindLibraryFeature(entry.Feature == DEFAULT + ? "__CMAKE_LINK_FRAMEWORK" + : entry.Feature)); + } else { + if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) { + this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes, + target, + this->FindLibraryFeature(entry.Feature)); + } else { + this->Items.emplace_back( + item, ItemIsPath::Yes, target, + this->FindLibraryFeature(entry.Feature == DEFAULT + ? "__CMAKE_LINK_LIBRARY" + : entry.Feature)); + } } } else { // Now add the full path to the library. this->Items.emplace_back( item, ItemIsPath::Yes, target, this->FindLibraryFeature( - entry.Feature == DEFAULT - ? (target->IsFrameworkOnApple() && this->GlobalGenerator->IsXcode() - ? "__CMAKE_LINK_FRAMEWORK" - : "__CMAKE_LINK_LIBRARY") - : entry.Feature)); + entry.Feature == DEFAULT ? "__CMAKE_LINK_LIBRARY" : entry.Feature)); } } diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index acf1c20..3149ccf 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -72,6 +72,10 @@ SETUP_LANGUAGE(swift_properties, Swift); std::string const kCMAKE_CUDA_ARCHITECTURES = "CMAKE_CUDA_ARCHITECTURES"; std::string const kCMAKE_CUDA_RUNTIME_LIBRARY = "CMAKE_CUDA_RUNTIME_LIBRARY"; std::string const kCMAKE_ENABLE_EXPORTS = "CMAKE_ENABLE_EXPORTS"; +std::string const kCMAKE_EXECUTABLE_ENABLE_EXPORTS = + "CMAKE_EXECUTABLE_ENABLE_EXPORTS"; +std::string const kCMAKE_SHARED_LIBRARY_ENABLE_EXPORTS = + "CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS"; std::string const kCMAKE_HIP_ARCHITECTURES = "CMAKE_HIP_ARCHITECTURES"; std::string const kCMAKE_HIP_RUNTIME_LIBRARY = "CMAKE_HIP_RUNTIME_LIBRARY"; std::string const kCMAKE_ISPC_INSTRUCTION_SETS = "CMAKE_ISPC_INSTRUCTION_SETS"; @@ -997,6 +1001,8 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( vars.insert(kCMAKE_CUDA_ARCHITECTURES); vars.insert(kCMAKE_CUDA_RUNTIME_LIBRARY); vars.insert(kCMAKE_ENABLE_EXPORTS); + vars.insert(kCMAKE_EXECUTABLE_ENABLE_EXPORTS); + vars.insert(kCMAKE_SHARED_LIBRARY_ENABLE_EXPORTS); vars.insert(kCMAKE_HIP_ARCHITECTURES); vars.insert(kCMAKE_HIP_RUNTIME_LIBRARY); vars.insert(kCMAKE_ISPC_INSTRUCTION_SETS); diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index ed199ea..caf8ac2 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -254,7 +254,7 @@ void cmExportBuildFileGenerator::SetImportLocationProperty( if (target->HasImportLibrary(config)) { std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix); std::string value = - target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact); + target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact, true); if (mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) { target->GetImplibGNUtoMS(config, value, value, "${CMAKE_IMPORT_LIBRARY_SUFFIX}"); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 7f1afba..6e7ef4e 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -1063,7 +1063,8 @@ void cmExportFileGenerator::GenerateImportTargetCode( } // Mark the imported executable if it has exports. - if (target->IsExecutableWithExports()) { + if (target->IsExecutableWithExports() || + (target->IsSharedLibraryWithExports() && target->HasImportLibrary(""))) { os << "set_property(TARGET " << targetName << " PROPERTY ENABLE_EXPORTS 1)\n"; } diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 5e190f4..def8227 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -409,7 +409,7 @@ void cmExportInstallFileGenerator::SetImportLocationProperty( // Append the installed file name. value += cmInstallTargetGenerator::GetInstallFilename( - target, config, cmInstallTargetGenerator::NameImplib); + target, config, cmInstallTargetGenerator::NameImplibReal); // Store the property. properties[prop] = value; @@ -430,6 +430,19 @@ void cmExportInstallFileGenerator::SetImportLocationProperty( properties[prop] = cmJoin(objects, ";"); importedLocations.insert(prop); } else { + if (target->IsFrameworkOnApple() && target->HasImportLibrary(config)) { + // store as well IMPLIB value + auto importProp = cmStrCat("IMPORTED_IMPLIB", suffix); + auto importValue = + cmStrCat(value, + cmInstallTargetGenerator::GetInstallFilename( + target, config, cmInstallTargetGenerator::NameImplibReal)); + + // Store the property. + properties[importProp] = importValue; + importedLocations.insert(importProp); + } + // Construct the property name. std::string prop = cmStrCat("IMPORTED_LOCATION", suffix); diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 8acfe83..4024dff 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -502,6 +502,7 @@ cmFindPackageCommand::cmFindPackageCommand(cmExecutionStatus& status) this->DebugMode = false; this->AppendSearchPathGroups(); + this->DeprecatedFindModules["CUDA"] = cmPolicies::CMP0146; this->DeprecatedFindModules["Dart"] = cmPolicies::CMP0145; this->DeprecatedFindModules["Qt"] = cmPolicies::CMP0084; } diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 5c7d217..6e78f55 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -2402,15 +2402,12 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode } } targetObjectsNode; -static const struct TargetRuntimeDllsNode : public cmGeneratorExpressionNode +struct TargetRuntimeDllsBaseNode : public cmGeneratorExpressionNode { - TargetRuntimeDllsNode() {} // NOLINT(modernize-use-equals-default) - - std::string Evaluate( + std::vector<std::string> CollectDlls( const std::vector<std::string>& parameters, cmGeneratorExpressionContext* context, - const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + const GeneratorExpressionContent* content) const { std::string const& tgtName = parameters.front(); cmGeneratorTarget* gt = context->LG->FindGeneratorTargetToUse(tgtName); @@ -2419,7 +2416,7 @@ static const struct TargetRuntimeDllsNode : public cmGeneratorExpressionNode e << "Objects of target \"" << tgtName << "\" referenced but no such target exists."; reportError(context, content->GetOriginalExpression(), e.str()); - return std::string(); + return std::vector<std::string>(); } cmStateEnums::TargetType type = gt->GetType(); if (type != cmStateEnums::EXECUTABLE && @@ -2430,7 +2427,7 @@ static const struct TargetRuntimeDllsNode : public cmGeneratorExpressionNode << "\" referenced but is not one of the allowed target types " << "(EXECUTABLE, SHARED, MODULE)."; reportError(context, content->GetOriginalExpression(), e.str()); - return std::string(); + return std::vector<std::string>(); } if (auto* cli = gt->GetLinkInformation(context->Config)) { @@ -2443,13 +2440,51 @@ static const struct TargetRuntimeDllsNode : public cmGeneratorExpressionNode } } - return cmJoin(dllPaths, ";"); + return dllPaths; } - return ""; + return std::vector<std::string>(); + } +}; + +static const struct TargetRuntimeDllsNode : public TargetRuntimeDllsBaseNode +{ + TargetRuntimeDllsNode() {} // NOLINT(modernize-use-equals-default) + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + std::vector<std::string> dlls = CollectDlls(parameters, context, content); + return cmJoin(dlls, ";"); } } targetRuntimeDllsNode; +static const struct TargetRuntimeDllDirsNode : public TargetRuntimeDllsBaseNode +{ + TargetRuntimeDllDirsNode() {} // NOLINT(modernize-use-equals-default) + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + std::vector<std::string> dlls = CollectDlls(parameters, context, content); + std::vector<std::string> dllDirs; + for (const std::string& dll : dlls) { + std::string directory = cmSystemTools::GetFilenamePath(dll); + if (std::find(dllDirs.begin(), dllDirs.end(), directory) == + dllDirs.end()) { + dllDirs.push_back(directory); + } + } + return cmJoin(dllDirs, ";"); + } +} targetRuntimeDllDirsNode; + static const struct CompileFeaturesNode : public cmGeneratorExpressionNode { CompileFeaturesNode() {} // NOLINT(modernize-use-equals-default) @@ -2658,10 +2693,14 @@ static const struct InstallPrefixNode : public cmGeneratorExpressionNode class ArtifactDirTag; class ArtifactLinkerTag; +class ArtifactLinkerLibraryTag; +class ArtifactLinkerImportTag; class ArtifactNameTag; +class ArtifactImportTag; class ArtifactPathTag; class ArtifactPdbTag; class ArtifactSonameTag; +class ArtifactSonameImportTag; class ArtifactBundleDirTag; class ArtifactBundleDirNameTag; class ArtifactBundleContentDirTag; @@ -2771,6 +2810,38 @@ struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag> }; template <> +struct TargetFilesystemArtifactResultCreator<ArtifactSonameImportTag> +{ + static std::string Create(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + // The target soname file (.so.1). + if (target->IsDLLPlatform()) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_SONAME_IMPORT_FILE is not allowed " + "for DLL target platforms."); + return std::string(); + } + if (target->GetType() != cmStateEnums::SHARED_LIBRARY) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_SONAME_IMPORT_FILE is allowed only for " + "SHARED libraries."); + return std::string(); + } + + if (target->HasImportLibrary(context->Config)) { + return cmStrCat(target->GetDirectory( + context->Config, cmStateEnums::ImportLibraryArtifact), + '/', + target->GetSOName(context->Config, + cmStateEnums::ImportLibraryArtifact)); + } + return std::string{}; + } +}; + +template <> struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag> { static std::string Create(cmGeneratorTarget* target, @@ -2817,7 +2888,8 @@ struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag> cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content) { - // The file used to link to the target (.so, .lib, .a). + // The file used to link to the target (.so, .lib, .a) or import file + // (.lib, .tbd). if (!target->IsLinkable()) { ::reportError(context, content->GetOriginalExpression(), "TARGET_LINKER_FILE is allowed only for libraries and " @@ -2833,6 +2905,55 @@ struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag> }; template <> +struct TargetFilesystemArtifactResultCreator<ArtifactLinkerLibraryTag> +{ + static std::string Create(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + // The file used to link to the target (.dylib, .so, .a). + if (!target->IsLinkable() || + target->GetType() == cmStateEnums::EXECUTABLE) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_LINKER_LIBRARY_FILE is allowed only for libraries " + "with ENABLE_EXPORTS."); + return std::string(); + } + + if (!target->IsDLLPlatform() || + target->GetType() == cmStateEnums::STATIC_LIBRARY) { + return target->GetFullPath(context->Config, + cmStateEnums::RuntimeBinaryArtifact); + } + return std::string{}; + } +}; + +template <> +struct TargetFilesystemArtifactResultCreator<ArtifactLinkerImportTag> +{ + static std::string Create(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + // The file used to link to the target (.lib, .tbd). + if (!target->IsLinkable()) { + ::reportError( + context, content->GetOriginalExpression(), + "TARGET_LINKER_IMPORT_FILE is allowed only for libraries and " + "executables with ENABLE_EXPORTS."); + return std::string(); + } + + if (target->HasImportLibrary(context->Config)) { + return target->GetFullPath(context->Config, + cmStateEnums::ImportLibraryArtifact); + } + return std::string{}; + } +}; + +template <> struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirTag> { static std::string Create(cmGeneratorTarget* target, @@ -2929,6 +3050,21 @@ struct TargetFilesystemArtifactResultCreator<ArtifactNameTag> } }; +template <> +struct TargetFilesystemArtifactResultCreator<ArtifactImportTag> +{ + static std::string Create(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* /*unused*/) + { + if (target->HasImportLibrary(context->Config)) { + return target->GetFullPath(context->Config, + cmStateEnums::ImportLibraryArtifact, true); + } + return std::string{}; + } +}; + template <typename ArtifactT> struct TargetFilesystemArtifactResultGetter { @@ -3054,12 +3190,24 @@ struct TargetFilesystemArtifactNodeGroup static const TargetFilesystemArtifactNodeGroup<ArtifactNameTag> targetNodeGroup; +static const TargetFilesystemArtifactNodeGroup<ArtifactImportTag> + targetImportNodeGroup; + static const TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag> targetLinkerNodeGroup; +static const TargetFilesystemArtifactNodeGroup<ArtifactLinkerLibraryTag> + targetLinkerLibraryNodeGroup; + +static const TargetFilesystemArtifactNodeGroup<ArtifactLinkerImportTag> + targetLinkerImportNodeGroup; + static const TargetFilesystemArtifactNodeGroup<ArtifactSonameTag> targetSoNameNodeGroup; +static const TargetFilesystemArtifactNodeGroup<ArtifactSonameImportTag> + targetSoNameImportNodeGroup; + static const TargetFilesystemArtifactNodeGroup<ArtifactPdbTag> targetPdbNodeGroup; @@ -3099,13 +3247,30 @@ struct TargetOutputNameArtifactResultGetter<ArtifactNameTag> }; template <> +struct TargetOutputNameArtifactResultGetter<ArtifactImportTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* /*unused*/) + { + if (target->HasImportLibrary(context->Config)) { + return target->GetOutputName(context->Config, + cmStateEnums::ImportLibraryArtifact) + + target->GetFilePostfix(context->Config); + } + return std::string{}; + } +}; + +template <> struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag> { static std::string Get(cmGeneratorTarget* target, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content) { - // The file used to link to the target (.so, .lib, .a). + // The library file used to link to the target (.so, .lib, .a) or import + // file (.lin, .tbd). if (!target->IsLinkable()) { ::reportError(context, content->GetOriginalExpression(), "TARGET_LINKER_FILE_BASE_NAME is allowed only for " @@ -3122,6 +3287,56 @@ struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag> }; template <> +struct TargetOutputNameArtifactResultGetter<ArtifactLinkerLibraryTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + // The library file used to link to the target (.so, .lib, .a). + if (!target->IsLinkable() || + target->GetType() == cmStateEnums::EXECUTABLE) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_LINKER_LIBRARY_FILE_BASE_NAME is allowed only for " + "libraries with ENABLE_EXPORTS."); + return std::string(); + } + + if (!target->IsDLLPlatform() || + target->GetType() == cmStateEnums::STATIC_LIBRARY) { + return target->GetOutputName(context->Config, + cmStateEnums::ImportLibraryArtifact) + + target->GetFilePostfix(context->Config); + } + return std::string{}; + } +}; + +template <> +struct TargetOutputNameArtifactResultGetter<ArtifactLinkerImportTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + // The import file used to link to the target (.lib, .tbd). + if (!target->IsLinkable()) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_LINKER_IMPORT_FILE_BASE_NAME is allowed only for " + "libraries and executables with ENABLE_EXPORTS."); + return std::string(); + } + + if (target->HasImportLibrary(context->Config)) { + return target->GetOutputName(context->Config, + cmStateEnums::ImportLibraryArtifact) + + target->GetFilePostfix(context->Config); + } + return std::string{}; + } +}; + +template <> struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag> { static std::string Get(cmGeneratorTarget* target, @@ -3192,15 +3407,27 @@ struct TargetFileBaseNameArtifact : public TargetArtifactBase static const TargetFileBaseNameArtifact<ArtifactNameTag> targetFileBaseNameNode; +static const TargetFileBaseNameArtifact<ArtifactImportTag> + targetImportFileBaseNameNode; static const TargetFileBaseNameArtifact<ArtifactLinkerTag> targetLinkerFileBaseNameNode; +static const TargetFileBaseNameArtifact<ArtifactLinkerLibraryTag> + targetLinkerLibraryFileBaseNameNode; +static const TargetFileBaseNameArtifact<ArtifactLinkerImportTag> + targetLinkerImportFileBaseNameNode; static const TargetFileBaseNameArtifact<ArtifactPdbTag> targetPdbFileBaseNameNode; class ArtifactFilePrefixTag; +class ArtifactImportFilePrefixTag; class ArtifactLinkerFilePrefixTag; +class ArtifactLinkerLibraryFilePrefixTag; +class ArtifactLinkerImportFilePrefixTag; class ArtifactFileSuffixTag; +class ArtifactImportFileSuffixTag; class ArtifactLinkerFileSuffixTag; +class ArtifactLinkerLibraryFileSuffixTag; +class ArtifactLinkerImportFileSuffixTag; template <typename ArtifactT> struct TargetFileArtifactResultGetter @@ -3221,6 +3448,20 @@ struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag> } }; template <> +struct TargetFileArtifactResultGetter<ArtifactImportFilePrefixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent*) + { + if (target->HasImportLibrary(context->Config)) { + return target->GetFilePrefix(context->Config, + cmStateEnums::ImportLibraryArtifact); + } + return std::string{}; + } +}; +template <> struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag> { static std::string Get(cmGeneratorTarget* target, @@ -3228,9 +3469,10 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag> const GeneratorExpressionContent* content) { if (!target->IsLinkable()) { - ::reportError(context, content->GetOriginalExpression(), - "TARGET_LINKER_PREFIX is allowed only for libraries and " - "executables with ENABLE_EXPORTS."); + ::reportError( + context, content->GetOriginalExpression(), + "TARGET_LINKER_FILE_PREFIX is allowed only for libraries and " + "executables with ENABLE_EXPORTS."); return std::string(); } @@ -3243,6 +3485,52 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag> } }; template <> +struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFilePrefixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + if (!target->IsLinkable() || + target->GetType() == cmStateEnums::EXECUTABLE) { + ::reportError( + context, content->GetOriginalExpression(), + "TARGET_LINKER_LIBRARY_FILE_PREFIX is allowed only for libraries " + "with ENABLE_EXPORTS."); + return std::string(); + } + + if (!target->IsDLLPlatform() || + target->GetType() == cmStateEnums::STATIC_LIBRARY) { + return target->GetFilePrefix(context->Config, + cmStateEnums::RuntimeBinaryArtifact); + } + return std::string{}; + } +}; +template <> +struct TargetFileArtifactResultGetter<ArtifactLinkerImportFilePrefixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + if (!target->IsLinkable()) { + ::reportError( + context, content->GetOriginalExpression(), + "TARGET_LINKER_IMPORT_FILE_PREFIX is allowed only for libraries and " + "executables with ENABLE_EXPORTS."); + return std::string(); + } + + if (target->HasImportLibrary(context->Config)) { + return target->GetFilePrefix(context->Config, + cmStateEnums::ImportLibraryArtifact); + } + return std::string{}; + } +}; +template <> struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag> { static std::string Get(cmGeneratorTarget* target, @@ -3253,6 +3541,20 @@ struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag> } }; template <> +struct TargetFileArtifactResultGetter<ArtifactImportFileSuffixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent*) + { + if (target->HasImportLibrary(context->Config)) { + return target->GetFileSuffix(context->Config, + cmStateEnums::ImportLibraryArtifact); + } + return std::string{}; + } +}; +template <> struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag> { static std::string Get(cmGeneratorTarget* target, @@ -3260,9 +3562,10 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag> const GeneratorExpressionContent* content) { if (!target->IsLinkable()) { - ::reportError(context, content->GetOriginalExpression(), - "TARGET_LINKER_SUFFIX is allowed only for libraries and " - "executables with ENABLE_EXPORTS."); + ::reportError( + context, content->GetOriginalExpression(), + "TARGET_LINKER_FILE_SUFFIX is allowed only for libraries and " + "executables with ENABLE_EXPORTS."); return std::string(); } @@ -3274,6 +3577,51 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag> return target->GetFileSuffix(context->Config, artifact); } }; +template <> +struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFileSuffixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + if (!target->IsLinkable() || + target->GetType() == cmStateEnums::STATIC_LIBRARY) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_LINKER_LIBRARY_FILE_SUFFIX is allowed only for " + "libraries with ENABLE_EXPORTS."); + return std::string(); + } + + if (!target->IsDLLPlatform() || + target->GetType() == cmStateEnums::STATIC_LIBRARY) { + return target->GetFileSuffix(context->Config, + cmStateEnums::RuntimeBinaryArtifact); + } + return std::string{}; + } +}; +template <> +struct TargetFileArtifactResultGetter<ArtifactLinkerImportFileSuffixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + if (!target->IsLinkable()) { + ::reportError( + context, content->GetOriginalExpression(), + "TARGET_LINKER_IMPORT_FILE_SUFFIX is allowed only for libraries and " + "executables with ENABLE_EXPORTS."); + return std::string(); + } + + if (target->HasImportLibrary(context->Config)) { + return target->GetFileSuffix(context->Config, + cmStateEnums::ImportLibraryArtifact); + } + return std::string{}; + } +}; template <typename ArtifactT> struct TargetFileArtifact : public TargetArtifactBase @@ -3304,11 +3652,23 @@ struct TargetFileArtifact : public TargetArtifactBase }; static const TargetFileArtifact<ArtifactFilePrefixTag> targetFilePrefixNode; +static const TargetFileArtifact<ArtifactImportFilePrefixTag> + targetImportFilePrefixNode; static const TargetFileArtifact<ArtifactLinkerFilePrefixTag> targetLinkerFilePrefixNode; +static const TargetFileArtifact<ArtifactLinkerLibraryFilePrefixTag> + targetLinkerLibraryFilePrefixNode; +static const TargetFileArtifact<ArtifactLinkerImportFilePrefixTag> + targetLinkerImportFilePrefixNode; static const TargetFileArtifact<ArtifactFileSuffixTag> targetFileSuffixNode; +static const TargetFileArtifact<ArtifactImportFileSuffixTag> + targetImportFileSuffixNode; static const TargetFileArtifact<ArtifactLinkerFileSuffixTag> targetLinkerFileSuffixNode; +static const TargetFileArtifact<ArtifactLinkerLibraryFileSuffixTag> + targetLinkerLibraryFileSuffixNode; +static const TargetFileArtifact<ArtifactLinkerImportFileSuffixTag> + targetLinkerImportFileSuffixNode; static const struct ShellPathNode : public cmGeneratorExpressionNode { @@ -3376,23 +3736,52 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "CONFIGURATION", &configurationNode }, { "CONFIG", &configurationTestNode }, { "TARGET_FILE", &targetNodeGroup.File }, + { "TARGET_IMPORT_FILE", &targetImportNodeGroup.File }, { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File }, + { "TARGET_LINKER_LIBRARY_FILE", &targetLinkerLibraryNodeGroup.File }, + { "TARGET_LINKER_IMPORT_FILE", &targetLinkerImportNodeGroup.File }, { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File }, + { "TARGET_SONAME_IMPORT_FILE", &targetSoNameImportNodeGroup.File }, { "TARGET_PDB_FILE", &targetPdbNodeGroup.File }, { "TARGET_FILE_BASE_NAME", &targetFileBaseNameNode }, + { "TARGET_IMPORT_FILE_BASE_NAME", &targetImportFileBaseNameNode }, { "TARGET_LINKER_FILE_BASE_NAME", &targetLinkerFileBaseNameNode }, + { "TARGET_LINKER_LIBRARY_FILE_BASE_NAME", + &targetLinkerLibraryFileBaseNameNode }, + { "TARGET_LINKER_IMPORT_FILE_BASE_NAME", + &targetLinkerImportFileBaseNameNode }, { "TARGET_PDB_FILE_BASE_NAME", &targetPdbFileBaseNameNode }, { "TARGET_FILE_PREFIX", &targetFilePrefixNode }, + { "TARGET_IMPORT_FILE_PREFIX", &targetImportFilePrefixNode }, { "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode }, + { "TARGET_LINKER_LIBRARY_FILE_PREFIX", + &targetLinkerLibraryFilePrefixNode }, + { "TARGET_LINKER_IMPORT_FILE_PREFIX", &targetLinkerImportFilePrefixNode }, { "TARGET_FILE_SUFFIX", &targetFileSuffixNode }, + { "TARGET_IMPORT_FILE_SUFFIX", &targetImportFileSuffixNode }, { "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode }, + { "TARGET_LINKER_LIBRARY_FILE_SUFFIX", + &targetLinkerLibraryFileSuffixNode }, + { "TARGET_LINKER_IMPORT_FILE_SUFFIX", &targetLinkerImportFileSuffixNode }, { "TARGET_FILE_NAME", &targetNodeGroup.FileName }, + { "TARGET_IMPORT_FILE_NAME", &targetImportNodeGroup.FileName }, { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName }, + { "TARGET_LINKER_LIBRARY_FILE_NAME", + &targetLinkerLibraryNodeGroup.FileName }, + { "TARGET_LINKER_IMPORT_FILE_NAME", + &targetLinkerImportNodeGroup.FileName }, { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName }, + { "TARGET_SONAME_IMPORT_FILE_NAME", + &targetSoNameImportNodeGroup.FileName }, { "TARGET_PDB_FILE_NAME", &targetPdbNodeGroup.FileName }, { "TARGET_FILE_DIR", &targetNodeGroup.FileDir }, + { "TARGET_IMPORT_FILE_DIR", &targetImportNodeGroup.FileDir }, { "TARGET_LINKER_FILE_DIR", &targetLinkerNodeGroup.FileDir }, + { "TARGET_LINKER_LIBRARY_FILE_DIR", + &targetLinkerLibraryNodeGroup.FileDir }, + { "TARGET_LINKER_IMPORT_FILE_DIR", &targetLinkerImportNodeGroup.FileDir }, { "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir }, + { "TARGET_SONAME_IMPORT_FILE_DIR", &targetSoNameImportNodeGroup.FileDir }, { "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir }, { "TARGET_BUNDLE_DIR", &targetBundleDirNode }, { "TARGET_BUNDLE_DIR_NAME", &targetBundleDirNameNode }, @@ -3420,6 +3809,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode }, { "TARGET_GENEX_EVAL", &targetGenexEvalNode }, { "TARGET_RUNTIME_DLLS", &targetRuntimeDllsNode }, + { "TARGET_RUNTIME_DLL_DIRS", &targetRuntimeDllDirsNode }, { "GENEX_EVAL", &genexEvalNode }, { "BUILD_INTERFACE", &buildInterfaceNode }, { "INSTALL_INTERFACE", &installInterfaceNode }, diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 112a87f..4cfa1d7 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -459,6 +459,11 @@ std::string const& cmGeneratorTarget::GetSafeProperty( const char* cmGeneratorTarget::GetOutputTargetType( cmStateEnums::ArtifactType artifact) const { + if (this->IsFrameworkOnApple() || this->GetGlobalGenerator()->IsXcode()) { + // import file (i.e. .tbd file) is always in same location as library + artifact = cmStateEnums::RuntimeBinaryArtifact; + } + switch (this->GetType()) { case cmStateEnums::SHARED_LIBRARY: if (this->IsDLLPlatform()) { @@ -471,9 +476,15 @@ const char* cmGeneratorTarget::GetOutputTargetType( return "ARCHIVE"; } } else { - // For non-DLL platforms shared libraries are treated as - // library targets. - return "LIBRARY"; + switch (artifact) { + case cmStateEnums::RuntimeBinaryArtifact: + // For non-DLL platforms shared libraries are treated as + // library targets. + return "LIBRARY"; + case cmStateEnums::ImportLibraryArtifact: + // Library import libraries are treated as archive targets. + return "ARCHIVE"; + } } break; case cmStateEnums::STATIC_LIBRARY: @@ -1730,7 +1741,8 @@ void addFileSetEntry(cmGeneratorTarget const* headTarget, std::move(entryCge), fileSet); entries.Entries.emplace_back( EvaluateTargetPropertyEntry(headTarget, config, "", dagChecker, tpe)); - for (auto const& file : entries.Entries.back().Values) { + EvaluatedTargetPropertyEntry const& entry = entries.Entries.back(); + for (auto const& file : entry.Values) { auto* sf = headTarget->Makefile->GetOrCreateSource(file); if (fileSet->GetType() == "HEADERS"_s) { sf->SetProperty("HEADER_FILE_ONLY", "TRUE"); @@ -1741,13 +1753,11 @@ void addFileSetEntry(cmGeneratorTarget const* headTarget, std::string w; auto path = sf->ResolveFullPath(&e, &w); if (!w.empty()) { - cm->IssueMessage(MessageType::AUTHOR_WARNING, w, - headTarget->GetBacktrace()); + cm->IssueMessage(MessageType::AUTHOR_WARNING, w, entry.Backtrace); } if (path.empty()) { if (!e.empty()) { - cm->IssueMessage(MessageType::FATAL_ERROR, e, - headTarget->GetBacktrace()); + cm->IssueMessage(MessageType::FATAL_ERROR, e, entry.Backtrace); } return; } @@ -1822,11 +1832,11 @@ bool processSources(cmGeneratorTarget const* tgt, std::string fullPath = sf->ResolveFullPath(&e, &w); cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance(); if (!w.empty()) { - cm->IssueMessage(MessageType::AUTHOR_WARNING, w, tgt->GetBacktrace()); + cm->IssueMessage(MessageType::AUTHOR_WARNING, w, entry.Backtrace); } if (fullPath.empty()) { if (!e.empty()) { - cm->IssueMessage(MessageType::FATAL_ERROR, e, tgt->GetBacktrace()); + cm->IssueMessage(MessageType::FATAL_ERROR, e, entry.Backtrace); } return contextDependent; } @@ -2534,7 +2544,8 @@ bool cmGeneratorTarget::CanGenerateInstallNameDir( return !skip; } -std::string cmGeneratorTarget::GetSOName(const std::string& config) const +std::string cmGeneratorTarget::GetSOName( + const std::string& config, cmStateEnums::ArtifactType artifact) const { if (this->IsImported()) { // Lookup the imported soname. @@ -2562,7 +2573,9 @@ std::string cmGeneratorTarget::GetSOName(const std::string& config) const return ""; } // Compute the soname that will be built. - return this->GetLibraryNames(config).SharedObject; + return artifact == cmStateEnums::RuntimeBinaryArtifact + ? this->GetLibraryNames(config).SharedObject + : this->GetLibraryNames(config).ImportLibrary; } namespace { @@ -3090,6 +3103,16 @@ void cmGeneratorTarget::ComputeModuleDefinitionInfo( } } +bool cmGeneratorTarget::IsAIX() const +{ + return this->Target->IsAIX(); +} + +bool cmGeneratorTarget::IsApple() const +{ + return this->Target->IsApple(); +} + bool cmGeneratorTarget::IsDLLPlatform() const { return this->Target->IsDLLPlatform(); @@ -3428,7 +3451,7 @@ std::string cmGeneratorTarget::GetCompilePDBDirectory( void cmGeneratorTarget::GetAppleArchs(const std::string& config, std::vector<std::string>& archVec) const { - if (!this->Makefile->IsOn("APPLE")) { + if (!this->IsApple()) { return; } cmValue archs = nullptr; @@ -3926,7 +3949,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang, &dagChecker, entries, IncludeRuntimeInterface::Yes); - if (this->Makefile->IsOn("APPLE")) { + if (this->IsApple()) { if (cmLinkImplementationLibraries const* impl = this->GetLinkImplementationLibraries(config, LinkInterfaceFor::Usage)) { @@ -5094,10 +5117,18 @@ void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const f = cmStrCat(dir, '/', targetNames.PDB); gg->AddToManifest(f); } + + dir = this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact); + if (!targetNames.ImportOutput.empty()) { + f = cmStrCat(dir, '/', targetNames.ImportOutput); + gg->AddToManifest(f); + } if (!targetNames.ImportLibrary.empty()) { - f = - cmStrCat(this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact), - '/', targetNames.ImportLibrary); + f = cmStrCat(dir, '/', targetNames.ImportLibrary); + gg->AddToManifest(f); + } + if (!targetNames.ImportReal.empty()) { + f = cmStrCat(dir, '/', targetNames.ImportReal); gg->AddToManifest(f); } } @@ -5217,14 +5248,20 @@ std::string cmGeneratorTarget::NormalGetFullPath( } break; case cmStateEnums::ImportLibraryArtifact: - fpath += this->GetFullName(config, cmStateEnums::ImportLibraryArtifact); + if (realname) { + fpath += + this->NormalGetRealName(config, cmStateEnums::ImportLibraryArtifact); + } else { + fpath += + this->GetFullName(config, cmStateEnums::ImportLibraryArtifact); + } break; } return fpath; } std::string cmGeneratorTarget::NormalGetRealName( - const std::string& config) const + const std::string& config, cmStateEnums::ArtifactType artifact) const { // This should not be called for imported targets. // TODO: Split cmTarget into a class hierarchy to get compile-time @@ -5235,12 +5272,13 @@ std::string cmGeneratorTarget::NormalGetRealName( this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg); } - if (this->GetType() == cmStateEnums::EXECUTABLE) { - // Compute the real name that will be built. - return this->GetExecutableNames(config).Real; - } + Names names = this->GetType() == cmStateEnums::EXECUTABLE + ? this->GetExecutableNames(config) + : this->GetLibraryNames(config); + // Compute the real name that will be built. - return this->GetLibraryNames(config).Real; + return artifact == cmStateEnums::RuntimeBinaryArtifact ? names.Real + : names.ImportReal; } cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames( @@ -5285,17 +5323,16 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames( // The library name. targetNames.Base = components.base; targetNames.Output = - components.prefix + targetNames.Base + components.suffix; + cmStrCat(components.prefix, targetNames.Base, components.suffix); if (this->IsFrameworkOnApple()) { targetNames.Real = components.prefix; if (!this->Makefile->PlatformIsAppleEmbedded()) { - targetNames.Real += "Versions/"; - targetNames.Real += this->GetFrameworkVersion(); - targetNames.Real += "/"; + targetNames.Real += + cmStrCat("Versions/", this->GetFrameworkVersion(), '/'); } - targetNames.Real += targetNames.Base + components.suffix; - targetNames.SharedObject = targetNames.Real + components.suffix; + targetNames.Real += cmStrCat(targetNames.Base, components.suffix); + targetNames.SharedObject = targetNames.Real; } else { // The library's soname. this->ComputeVersionedName(targetNames.SharedObject, components.prefix, @@ -5308,11 +5345,36 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames( targetNames.Output, version); } - // The import library name. + // The import library names. if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::MODULE_LIBRARY) { - targetNames.ImportLibrary = - this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact); + NameComponents const& importComponents = + this->GetFullNameInternalComponents(config, + cmStateEnums::ImportLibraryArtifact); + targetNames.ImportOutput = cmStrCat( + importComponents.prefix, importComponents.base, importComponents.suffix); + + if (this->IsFrameworkOnApple() && this->IsSharedLibraryWithExports()) { + targetNames.ImportReal = components.prefix; + if (!this->Makefile->PlatformIsAppleEmbedded()) { + targetNames.ImportReal += + cmStrCat("Versions/", this->GetFrameworkVersion(), '/'); + } + targetNames.ImportReal += + cmStrCat(importComponents.base, importComponents.suffix); + targetNames.ImportLibrary = targetNames.ImportOutput; + } else { + // The import library's soname. + this->ComputeVersionedName( + targetNames.ImportLibrary, importComponents.prefix, + importComponents.base, importComponents.suffix, + targetNames.ImportOutput, soversion); + + // The import library's real name on disk. + this->ComputeVersionedName( + targetNames.ImportReal, importComponents.prefix, importComponents.base, + importComponents.suffix, targetNames.ImportOutput, version); + } } // The program database file name. @@ -5374,6 +5436,8 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames( // The import library name. targetNames.ImportLibrary = this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact); + targetNames.ImportReal = targetNames.ImportLibrary; + targetNames.ImportOutput = targetNames.ImportLibrary; // The program database file name. targetNames.PDB = this->GetPDBName(config); @@ -5455,15 +5519,18 @@ cmGeneratorTarget::GetFullNameInternalComponents( } // Compute the full name for main target types. - const std::string configPostfix = this->GetFilePostfix(config); + std::string configPostfix = this->GetFilePostfix(config); - // frameworks have directory prefix but no suffix + // frameworks have directory prefix std::string fw_prefix; if (this->IsFrameworkOnApple()) { fw_prefix = cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/'); targetPrefix = cmValue(fw_prefix); - targetSuffix = nullptr; + if (!isImportedLibraryArtifact) { + // no suffix + targetSuffix = nullptr; + } } if (this->IsCFBundleOnApple()) { @@ -5482,8 +5549,8 @@ cmGeneratorTarget::GetFullNameInternalComponents( // When using Xcode, the postfix should be part of the suffix rather than // the base, because the suffix ends up being used in Xcode's // EXECUTABLE_SUFFIX attribute. - if (this->IsFrameworkOnApple() && - this->GetGlobalGenerator()->GetName() == "Xcode") { + if (this->IsFrameworkOnApple() && this->GetGlobalGenerator()->IsXcode()) { + configPostfix += *targetSuffix; targetSuffix = cmValue(configPostfix); } else { outBase += configPostfix; @@ -6779,12 +6846,12 @@ void cmGeneratorTarget::ComputeVersionedName( std::string& vName, std::string const& prefix, std::string const& base, std::string const& suffix, std::string const& name, cmValue version) const { - vName = this->Makefile->IsOn("APPLE") ? (prefix + base) : name; + vName = this->IsApple() ? (prefix + base) : name; if (version) { vName += "."; vName += *version; } - vName += this->Makefile->IsOn("APPLE") ? suffix : std::string(); + vName += this->IsApple() ? suffix : std::string(); } std::vector<std::string> cmGeneratorTarget::GetPropertyKeys() const @@ -8553,19 +8620,38 @@ bool cmGeneratorTarget::HasContextDependentSources() const bool cmGeneratorTarget::IsExecutableWithExports() const { - return (this->GetType() == cmStateEnums::EXECUTABLE && - this->GetPropertyAsBool("ENABLE_EXPORTS")); + return this->Target->IsExecutableWithExports(); +} + +bool cmGeneratorTarget::IsSharedLibraryWithExports() const +{ + return this->Target->IsSharedLibraryWithExports(); } bool cmGeneratorTarget::HasImportLibrary(std::string const& config) const { + bool generate_Stubs = true; + if (this->GetGlobalGenerator()->IsXcode()) { + // take care of CMAKE_XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS variable + // as well as XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS property + if (cmValue propGenStubs = + this->GetProperty("XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS")) { + generate_Stubs = propGenStubs == "YES"; + } else if (cmValue varGenStubs = this->Makefile->GetDefinition( + "CMAKE_XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS")) { + generate_Stubs = varGenStubs == "YES"; + } + } + return (this->IsDLLPlatform() && (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->IsExecutableWithExports()) && // Assemblies which have only managed code do not have // import libraries. this->GetManagedType(config) != ManagedType::Managed) || - (this->Target->IsAIX() && this->IsExecutableWithExports()); + (this->IsAIX() && this->IsExecutableWithExports()) || + (this->Makefile->PlatformSupportsAppleTextStubs() && + this->IsSharedLibraryWithExports() && generate_Stubs); } bool cmGeneratorTarget::NeedImportLibraryName(std::string const& config) const @@ -8603,17 +8689,12 @@ bool cmGeneratorTarget::IsLinkable() const bool cmGeneratorTarget::IsFrameworkOnApple() const { - return ((this->GetType() == cmStateEnums::SHARED_LIBRARY || - this->GetType() == cmStateEnums::STATIC_LIBRARY) && - this->Makefile->IsOn("APPLE") && - this->GetPropertyAsBool("FRAMEWORK")); + return this->Target->IsFrameworkOnApple(); } bool cmGeneratorTarget::IsAppBundleOnApple() const { - return (this->GetType() == cmStateEnums::EXECUTABLE && - this->Makefile->IsOn("APPLE") && - this->GetPropertyAsBool("MACOSX_BUNDLE")); + return this->Target->IsAppBundleOnApple(); } bool cmGeneratorTarget::IsXCTestOnApple() const @@ -8623,8 +8704,8 @@ bool cmGeneratorTarget::IsXCTestOnApple() const bool cmGeneratorTarget::IsCFBundleOnApple() const { - return (this->GetType() == cmStateEnums::MODULE_LIBRARY && - this->Makefile->IsOn("APPLE") && this->GetPropertyAsBool("BUNDLE")); + return (this->GetType() == cmStateEnums::MODULE_LIBRARY && this->IsApple() && + this->GetPropertyAsBool("BUNDLE")); } cmGeneratorTarget::ManagedType cmGeneratorTarget::CheckManagedType( diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index e46c719..5d26191 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -273,7 +273,9 @@ public: std::string NormalGetFullPath(const std::string& config, cmStateEnums::ArtifactType artifact, bool realname) const; - std::string NormalGetRealName(const std::string& config) const; + std::string NormalGetRealName(const std::string& config, + cmStateEnums::ArtifactType artifact = + cmStateEnums::RuntimeBinaryArtifact) const; /** Get the names of an object library's object files underneath its object file directory. */ @@ -348,7 +350,9 @@ public: const std::string* GetExportMacro() const; /** Get the soname of the target. Allowed only for a shared library. */ - std::string GetSOName(const std::string& config) const; + std::string GetSOName(const std::string& config, + cmStateEnums::ArtifactType artifact = + cmStateEnums::RuntimeBinaryArtifact) const; struct NameComponents { @@ -389,6 +393,11 @@ public: ModuleDefinitionInfo const* GetModuleDefinitionInfo( std::string const& config) const; + /** Return whether or not we are targeting AIX. */ + bool IsAIX() const; + /** Return whether or not we are targeting Apple. */ + bool IsApple() const; + /** Return whether or not the target is for a DLL platform. */ bool IsDLLPlatform() const; @@ -735,6 +744,8 @@ public: std::string Base; std::string Output; std::string Real; + std::string ImportOutput; + std::string ImportReal; std::string ImportLibrary; std::string PDB; std::string SharedObject; @@ -781,6 +792,10 @@ public: bool IsExecutableWithExports() const; + /* Return whether this target is a shared library with capability to generate + * a file describing symbols exported (for example, .tbd file on Apple). */ + bool IsSharedLibraryWithExports() const; + /** Return whether or not the target has a DLL import library. */ bool HasImportLibrary(std::string const& config) const; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index b5e1529..650d0aa 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -8,7 +8,6 @@ #include <cstdio> #include <functional> #include <sstream> -#include <tuple> #include <utility> #include <cm/iterator> @@ -571,6 +570,7 @@ void cmGlobalNinjaGenerator::Generate() msg.str()); return; } + this->InitOutputPathPrefix(); if (!this->OpenBuildFileStreams()) { return; } @@ -579,10 +579,9 @@ void cmGlobalNinjaGenerator::Generate() } for (auto& it : this->Configs) { - it.second.TargetDependsClosureLocalOutputs.clear(); + it.second.TargetDependsClosures.clear(); } - this->InitOutputPathPrefix(); this->TargetAll = this->NinjaOutputPath("all"); this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt"); this->DiagnosedCxxModuleNinjaSupport = false; @@ -1270,6 +1269,10 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( } CM_FALLTHROUGH; case cmStateEnums::EXECUTABLE: { + if (target->IsApple() && target->HasImportLibrary(config)) { + outputs.push_back(this->ConvertToNinjaPath(target->GetFullPath( + config, cmStateEnums::ImportLibraryArtifact, realname))); + } outputs.push_back(this->ConvertToNinjaPath(target->GetFullPath( config, cmStateEnums::RuntimeBinaryArtifact, realname))); break; @@ -1359,85 +1362,70 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure( cmGeneratorTarget const* target, cmNinjaDeps& outputs, const std::string& config, const std::string& fileConfig, bool genexOutput) { - struct Entry - { - Entry(cmGeneratorTarget const* target_, std::string config_, - std::string fileConfig_) - : target(target_) - , config(std::move(config_)) - , fileConfig(std::move(fileConfig_)) - { - } + cmNinjaOuts outs; + this->AppendTargetDependsClosure(target, outs, config, fileConfig, + genexOutput, true); + cm::append(outputs, outs); +} - bool operator<(Entry const& other) const - { - return std::tie(target, config, fileConfig) < - std::tie(other.target, other.config, other.fileConfig); - } +void cmGlobalNinjaGenerator::AppendTargetDependsClosure( + cmGeneratorTarget const* target, cmNinjaOuts& outputs, + const std::string& config, const std::string& fileConfig, bool genexOutput, + bool omit_self) +{ - cmGeneratorTarget const* target; - std::string config; - std::string fileConfig; + // try to locate the target in the cache + ByConfig::TargetDependsClosureKey key{ + target, + config, + genexOutput, }; - - cmNinjaOuts outputSet; - std::vector<Entry> stack; - stack.emplace_back(target, config, fileConfig); - std::set<Entry> seen = { stack.back() }; - - do { - Entry entry = std::move(stack.back()); - stack.pop_back(); - - // generate the outputs of the target itself, if applicable - if (entry.target != target) { - // try to locate the target in the cache - ByConfig::TargetDependsClosureKey localCacheKey{ - entry.target, - entry.config, - genexOutput, - }; - auto& configs = this->Configs[entry.fileConfig]; - auto lb = - configs.TargetDependsClosureLocalOutputs.lower_bound(localCacheKey); - - if (lb == configs.TargetDependsClosureLocalOutputs.end() || - lb->first != localCacheKey) { - cmNinjaDeps outs; - this->AppendTargetOutputs(entry.target, outs, entry.config, - DependOnTargetArtifact); - configs.TargetDependsClosureLocalOutputs.emplace_hint( - lb, localCacheKey, outs); - for (auto& value : outs) { - outputSet.emplace(std::move(value)); - } - } else { - outputSet.insert(lb->second.begin(), lb->second.end()); - } - } - - // push next dependencies - for (const auto& dep_target : this->GetTargetDirectDepends(entry.target)) { + auto find = this->Configs[fileConfig].TargetDependsClosures.lower_bound(key); + + if (find == this->Configs[fileConfig].TargetDependsClosures.end() || + find->first != key) { + // We now calculate the closure outputs by inspecting the dependent + // targets recursively. + // For that we have to distinguish between a local result set that is only + // relevant for filling the cache entries properly isolated and a global + // result set that is relevant for the result of the top level call to + // AppendTargetDependsClosure. + cmNinjaOuts this_outs; // this will be the new cache entry + + for (auto const& dep_target : this->GetTargetDirectDepends(target)) { if (!dep_target->IsInBuildSystem()) { continue; } - if (!this->IsSingleConfigUtility(entry.target) && + if (!this->IsSingleConfigUtility(target) && !this->IsSingleConfigUtility(dep_target) && this->EnableCrossConfigBuild() && !dep_target.IsCross() && !genexOutput) { continue; } - auto emplaceRes = seen.emplace( - dep_target, dep_target.IsCross() ? entry.fileConfig : entry.config, - entry.fileConfig); - if (emplaceRes.second) { - stack.emplace_back(*emplaceRes.first); + if (dep_target.IsCross()) { + this->AppendTargetDependsClosure(dep_target, this_outs, fileConfig, + fileConfig, genexOutput, false); + } else { + this->AppendTargetDependsClosure(dep_target, this_outs, config, + fileConfig, genexOutput, false); } } - } while (!stack.empty()); - cm::append(outputs, outputSet); + find = this->Configs[fileConfig].TargetDependsClosures.emplace_hint( + find, key, std::move(this_outs)); + } + + // now fill the outputs of the final result from the newly generated cache + // entry + outputs.insert(find->second.begin(), find->second.end()); + + // finally generate the outputs of the target itself, if applicable + cmNinjaDeps outs; + if (!omit_self) { + this->AppendTargetOutputs(target, outs, config, DependOnTargetArtifact); + } + outputs.insert(outs.begin(), outs.end()); } void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias, @@ -2075,9 +2063,10 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) build.Outputs.front() = this->BuildAlias( this->NinjaOutputPath(this->GetCleanTargetName()), config); if (this->IsMultiConfig()) { - build.Variables["TARGETS"] = - cmStrCat(this->BuildAlias(GetByproductsForCleanTargetName(), config), - " ", GetByproductsForCleanTargetName()); + build.Variables["TARGETS"] = cmStrCat( + this->BuildAlias( + this->NinjaOutputPath(GetByproductsForCleanTargetName()), config), + " ", this->NinjaOutputPath(GetByproductsForCleanTargetName())); } build.ExplicitDeps.clear(); if (additionalFiles) { @@ -2092,7 +2081,8 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) if (this->IsMultiConfig()) { build.Variables["FILE_ARG"] = cmStrCat( "-f ", - cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig)); + this->NinjaOutputPath( + cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig))); } this->WriteBuild(*this->GetImplFileStream(fileConfig), build); } @@ -2114,8 +2104,8 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) std::vector<std::string> byproducts; byproducts.reserve(this->CrossConfigs.size()); for (auto const& config : this->CrossConfigs) { - byproducts.push_back( - this->BuildAlias(GetByproductsForCleanTargetName(), config)); + byproducts.push_back(this->BuildAlias( + this->NinjaOutputPath(GetByproductsForCleanTargetName()), config)); } byproducts.emplace_back(GetByproductsForCleanTargetName()); build.Variables["TARGETS"] = cmJoin(byproducts, " "); @@ -2123,7 +2113,8 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) for (auto const& fileConfig : configs) { build.Variables["FILE_ARG"] = cmStrCat( "-f ", - cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig)); + this->NinjaOutputPath( + cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig))); this->WriteBuild(*this->GetImplFileStream(fileConfig), build); } } @@ -2906,7 +2897,8 @@ bool cmGlobalNinjaMultiGenerator::OpenBuildFileStreams() *this->DefaultFileStream << "# Build using rules for '" << this->DefaultFileConfig << "'.\n\n" << "include " - << GetNinjaImplFilename(this->DefaultFileConfig) + << this->NinjaOutputPath( + GetNinjaImplFilename(this->DefaultFileConfig)) << "\n\n"; // Write a comment about this file. @@ -2939,7 +2931,8 @@ bool cmGlobalNinjaMultiGenerator::OpenBuildFileStreams() *this->ConfigFileStreams[config] << "# This file contains aliases specific to the \"" << config << "\"\n# configuration.\n\n" - << "include " << GetNinjaImplFilename(config) << "\n\n"; + << "include " << this->NinjaOutputPath(GetNinjaImplFilename(config)) + << "\n\n"; return true; }); diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 6d23e89..c08bb46 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -354,6 +354,11 @@ public: const std::string& config, const std::string& fileConfig, bool genexOutput); + void AppendTargetDependsClosure(cmGeneratorTarget const* target, + cmNinjaOuts& outputs, + const std::string& config, + const std::string& fileConfig, + bool genexOutput, bool omit_self); void AppendDirectoryForConfig(const std::string& prefix, const std::string& config, @@ -611,8 +616,7 @@ private: bool GenexOutput; }; - std::map<TargetDependsClosureKey, cmNinjaDeps> - TargetDependsClosureLocalOutputs; + std::map<TargetDependsClosureKey, cmNinjaOuts> TargetDependsClosures; TargetAliasMap TargetAliases; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index d4ce69e..5b3ac60 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1739,7 +1739,7 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( std::string str_so_file = cmStrCat("$<TARGET_SONAME_FILE:", gtgt->GetName(), '>'); std::string str_link_file = - cmStrCat("$<TARGET_LINKER_FILE:", gtgt->GetName(), '>'); + cmStrCat("$<TARGET_LINKER_LIBRARY_FILE:", gtgt->GetName(), '>'); cmCustomCommandLines cmd = cmMakeSingleCommandLine( { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library", str_file, str_so_file, str_link_file }); @@ -1754,6 +1754,27 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( postbuild.push_back(std::move(command)); } + if (gtgt->HasImportLibrary("") && !gtgt->IsFrameworkOnApple()) { + // create symbolic links for .tbd file + std::string file = cmStrCat("$<TARGET_IMPORT_FILE:", gtgt->GetName(), '>'); + std::string soFile = + cmStrCat("$<TARGET_SONAME_IMPORT_FILE:", gtgt->GetName(), '>'); + std::string linkFile = + cmStrCat("$<TARGET_LINKER_IMPORT_FILE:", gtgt->GetName(), '>'); + cmCustomCommandLines symlink_command = cmMakeSingleCommandLine( + { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library", file, + soFile, linkFile }); + + cmCustomCommand command; + command.SetCommandLines(symlink_command); + command.SetComment("Creating import symlinks"); + command.SetWorkingDirectory(""); + command.SetBacktrace(this->CurrentMakefile->GetBacktrace()); + command.SetStdPipesUTF8(true); + + postbuild.push_back(std::move(command)); + } + cmXCodeObject* legacyCustomCommandsBuildPhase = nullptr; cmXCodeObject* preBuildPhase = nullptr; cmXCodeObject* preLinkPhase = nullptr; @@ -2682,6 +2703,12 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, buildSettings->AddAttribute("LIBRARY_STYLE", this->CreateString("DYNAMIC")); + + if (gtgt->HasImportLibrary(configName)) { + // Request .tbd file generation + buildSettings->AddAttribute("GENERATE_TEXT_BASED_STUBS", + this->CreateString("YES")); + } break; } case cmStateEnums::EXECUTABLE: { diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx index 3564cf7..56883fb 100644 --- a/Source/cmIncludeCommand.cxx +++ b/Source/cmIncludeCommand.cxx @@ -22,6 +22,7 @@ bool cmIncludeCommand(std::vector<std::string> const& args, if (DeprecatedModules.empty()) { DeprecatedModules["Dart"] = cmPolicies::CMP0145; DeprecatedModules["Documentation"] = cmPolicies::CMP0106; + DeprecatedModules["FindCUDA"] = cmPolicies::CMP0146; DeprecatedModules["FindDart"] = cmPolicies::CMP0145; DeprecatedModules["WriteCompilerDetectionHeader"] = cmPolicies::CMP0120; } diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 56c8b26..40230d9 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -553,34 +553,35 @@ bool HandleTargetsMode(std::vector<std::string> const& args, // Enforce argument rules too complex to specify for the // general-purpose parser. - if (archiveArgs.GetNamelinkOnly() || runtimeArgs.GetNamelinkOnly() || - objectArgs.GetNamelinkOnly() || frameworkArgs.GetNamelinkOnly() || - bundleArgs.GetNamelinkOnly() || privateHeaderArgs.GetNamelinkOnly() || + if (runtimeArgs.GetNamelinkOnly() || objectArgs.GetNamelinkOnly() || + frameworkArgs.GetNamelinkOnly() || bundleArgs.GetNamelinkOnly() || + privateHeaderArgs.GetNamelinkOnly() || publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly() || std::any_of(fileSetArgs.begin(), fileSetArgs.end(), [](const cmInstallCommandFileSetArguments& fileSetArg) -> bool { return fileSetArg.GetNamelinkOnly(); }) || cxxModuleBmiArgs.GetNamelinkOnly()) { status.SetError( - "TARGETS given NAMELINK_ONLY option not in LIBRARY group. " - "The NAMELINK_ONLY option may be specified only following LIBRARY."); + "TARGETS given NAMELINK_ONLY option not in LIBRARY or ARCHIVE group. " + "The NAMELINK_ONLY option may be specified only following LIBRARY or " + "ARCHIVE."); return false; } - if (archiveArgs.GetNamelinkSkip() || runtimeArgs.GetNamelinkSkip() || - objectArgs.GetNamelinkSkip() || frameworkArgs.GetNamelinkSkip() || - bundleArgs.GetNamelinkSkip() || privateHeaderArgs.GetNamelinkSkip() || + if (runtimeArgs.GetNamelinkSkip() || objectArgs.GetNamelinkSkip() || + frameworkArgs.GetNamelinkSkip() || bundleArgs.GetNamelinkSkip() || + privateHeaderArgs.GetNamelinkSkip() || publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip() || std::any_of(fileSetArgs.begin(), fileSetArgs.end(), [](const cmInstallCommandFileSetArguments& fileSetArg) -> bool { return fileSetArg.GetNamelinkSkip(); }) || cxxModuleBmiArgs.GetNamelinkSkip()) { status.SetError( - "TARGETS given NAMELINK_SKIP option not in LIBRARY group. " - "The NAMELINK_SKIP option may be specified only following LIBRARY."); + "TARGETS given NAMELINK_SKIP option not in LIBRARY or ARCHIVE group. " + "The NAMELINK_SKIP option may be specified only following LIBRARY or " + "ARCHIVE."); return false; } - if (archiveArgs.HasNamelinkComponent() || - runtimeArgs.HasNamelinkComponent() || + if (runtimeArgs.HasNamelinkComponent() || objectArgs.HasNamelinkComponent() || frameworkArgs.HasNamelinkComponent() || bundleArgs.HasNamelinkComponent() || @@ -592,9 +593,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, -> bool { return fileSetArg.HasNamelinkComponent(); }) || cxxModuleBmiArgs.HasNamelinkComponent()) { status.SetError( - "TARGETS given NAMELINK_COMPONENT option not in LIBRARY group. " - "The NAMELINK_COMPONENT option may be specified only following " - "LIBRARY."); + "TARGETS given NAMELINK_COMPONENT option not in LIBRARY or ARCHIVE " + "group. The NAMELINK_COMPONENT option may be specified only following " + "LIBRARY or ARCHIVE."); return false; } if (libraryArgs.GetNamelinkOnly() && libraryArgs.GetNamelinkSkip()) { @@ -674,6 +675,14 @@ bool HandleTargetsMode(std::vector<std::string> const& args, } else if (libraryArgs.GetNamelinkSkip()) { namelinkMode = cmInstallTargetGenerator::NamelinkModeSkip; } + // Select the mode for installing symlinks to versioned imported libraries. + cmInstallTargetGenerator::NamelinkModeType importlinkMode = + cmInstallTargetGenerator::NamelinkModeNone; + if (archiveArgs.GetNamelinkOnly()) { + importlinkMode = cmInstallTargetGenerator::NamelinkModeOnly; + } else if (archiveArgs.GetNamelinkSkip()) { + importlinkMode = cmInstallTargetGenerator::NamelinkModeSkip; + } // Check if there is something to do. if (targetList.empty()) { @@ -725,6 +734,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, bool installsArchive = false; bool installsLibrary = false; bool installsNamelink = false; + bool installsImportlink = false; bool installsRuntime = false; bool installsObject = false; bool installsFramework = false; @@ -742,6 +752,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, std::unique_ptr<cmInstallTargetGenerator> archiveGenerator; std::unique_ptr<cmInstallTargetGenerator> libraryGenerator; std::unique_ptr<cmInstallTargetGenerator> namelinkGenerator; + std::unique_ptr<cmInstallTargetGenerator> importlinkGenerator; std::unique_ptr<cmInstallTargetGenerator> runtimeGenerator; std::unique_ptr<cmInstallTargetGenerator> objectGenerator; std::unique_ptr<cmInstallTargetGenerator> frameworkGenerator; @@ -885,6 +896,32 @@ bool HandleTargetsMode(std::vector<std::string> const& args, } namelinkOnly = (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly); + + if (target.GetMakefile()->PlatformSupportsAppleTextStubs() && + target.IsSharedLibraryWithExports()) { + // Apple .tbd files use the ARCHIVE properties + if (!archiveArgs.GetDestination().empty()) { + artifactsSpecified = true; + } + if (importlinkMode != + cmInstallTargetGenerator::NamelinkModeOnly) { + archiveGenerator = CreateInstallTargetGenerator( + target, archiveArgs, true, helper.Makefile->GetBacktrace(), + helper.GetLibraryDestination(&archiveArgs)); + archiveGenerator->SetImportlinkMode( + cmInstallTargetGenerator::NamelinkModeSkip); + } + if (importlinkMode != + cmInstallTargetGenerator::NamelinkModeSkip) { + importlinkGenerator = CreateInstallTargetGenerator( + target, archiveArgs, true, helper.Makefile->GetBacktrace(), + helper.GetLibraryDestination(&archiveArgs), false, true); + importlinkGenerator->SetImportlinkMode( + cmInstallTargetGenerator::NamelinkModeOnly); + } + namelinkOnly = + (importlinkMode == cmInstallTargetGenerator::NamelinkModeOnly); + } } if (runtimeDependencySet && libraryGenerator) { runtimeDependencySet->AddLibrary(libraryGenerator.get()); @@ -1157,6 +1194,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, installsArchive = installsArchive || archiveGenerator; installsLibrary = installsLibrary || libraryGenerator; installsNamelink = installsNamelink || namelinkGenerator; + installsImportlink = installsImportlink || importlinkGenerator; installsRuntime = installsRuntime || runtimeGenerator; installsObject = installsObject || objectGenerator; installsFramework = installsFramework || frameworkGenerator; @@ -1169,6 +1207,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, helper.Makefile->AddInstallGenerator(std::move(archiveGenerator)); helper.Makefile->AddInstallGenerator(std::move(libraryGenerator)); helper.Makefile->AddInstallGenerator(std::move(namelinkGenerator)); + helper.Makefile->AddInstallGenerator(std::move(importlinkGenerator)); helper.Makefile->AddInstallGenerator(std::move(runtimeGenerator)); helper.Makefile->AddInstallGenerator(std::move(objectGenerator)); helper.Makefile->AddInstallGenerator(std::move(frameworkGenerator)); @@ -1203,6 +1242,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args, helper.Makefile->GetGlobalGenerator()->AddInstallComponent( libraryArgs.GetNamelinkComponent()); } + if (installsImportlink) { + helper.Makefile->GetGlobalGenerator()->AddInstallComponent( + archiveArgs.GetNamelinkComponent()); + } if (installsRuntime) { helper.Makefile->GetGlobalGenerator()->AddInstallComponent( runtimeArgs.GetComponent()); diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 16c5002..6c31da6 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -4,12 +4,15 @@ #include <algorithm> #include <cassert> +#include <functional> #include <map> #include <set> #include <sstream> #include <utility> #include <vector> +#include <cm/optional> + #include "cmComputeLinkInformation.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" @@ -40,6 +43,84 @@ std::string computeInstallObjectDir(cmGeneratorTarget* gt, objectDir += gt->GetName(); return objectDir; } + +void computeFilesToInstall( + cmInstallTargetGenerator::Files& files, + cmInstallTargetGenerator::NamelinkModeType namelinkMode, + std::string const& fromDirConfig, std::string const& output, + std::string const& library, std::string const& real, + cm::optional<std::function<void(std::string const&)>> GNUToMS = cm::nullopt) +{ + bool haveNamelink = false; + auto convert = [&GNUToMS](std::string const& file) { + if (GNUToMS) { + (*GNUToMS)(file); + } + }; + + // Library link name. + std::string fromName = cmStrCat(fromDirConfig, output); + std::string toName = output; + + // Library interface name. + std::string fromSOName; + std::string toSOName; + if (library != output) { + haveNamelink = true; + fromSOName = cmStrCat(fromDirConfig, library); + toSOName = library; + } + + // Library implementation name. + std::string fromRealName; + std::string toRealName; + if (real != output && real != library) { + haveNamelink = true; + fromRealName = cmStrCat(fromDirConfig, real); + toRealName = real; + } + + // Add the names based on the current namelink mode. + if (haveNamelink) { + files.NamelinkMode = namelinkMode; + // With a namelink we need to check the mode. + if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { + // Install the namelink only. + files.From.emplace_back(fromName); + files.To.emplace_back(toName); + convert(output); + } else { + // Install the real file if it has its own name. + if (!fromRealName.empty()) { + files.From.emplace_back(fromRealName); + files.To.emplace_back(toRealName); + convert(real); + } + + // Install the soname link if it has its own name. + if (!fromSOName.empty()) { + files.From.emplace_back(fromSOName); + files.To.emplace_back(toSOName); + convert(library); + } + + // Install the namelink if it is not to be skipped. + if (namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) { + files.From.emplace_back(fromName); + files.To.emplace_back(toName); + convert(output); + } + } + } else { + // Without a namelink there will be only one file. Install it + // if this is not a namelink-only rule. + if (namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) { + files.From.emplace_back(fromName); + files.To.emplace_back(toName); + convert(output); + } + } +} } cmInstallTargetGenerator::cmInstallTargetGenerator( @@ -56,6 +137,7 @@ cmInstallTargetGenerator::cmInstallTargetGenerator( { this->ActionsPerConfig = true; this->NamelinkMode = NamelinkModeNone; + this->ImportlinkMode = NamelinkModeNone; } cmInstallTargetGenerator::~cmInstallTargetGenerator() = default; @@ -247,18 +329,21 @@ cmInstallTargetGenerator::Files cmInstallTargetGenerator::GetFiles( this->Target->GetLibraryNames(config); if (this->ImportLibrary) { // There is a bug in cmInstallCommand if this fails. - assert(this->NamelinkMode == NamelinkModeNone); + assert(this->Target->Makefile->PlatformSupportsAppleTextStubs() || + this->ImportlinkMode == NamelinkModeNone); + + auto GNUToMS = [this, &config, &files, + &fromDirConfig](const std::string& lib) { + std::string importLib; + if (this->Target->GetImplibGNUtoMS(config, lib, importLib)) { + files.From.emplace_back(fromDirConfig + importLib); + files.To.emplace_back(importLib); + } + }; - std::string from1 = fromDirConfig + targetNames.ImportLibrary; - std::string to1 = targetNames.ImportLibrary; - files.From.emplace_back(std::move(from1)); - files.To.emplace_back(std::move(to1)); - std::string targetNameImportLib; - if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, - targetNameImportLib)) { - files.From.emplace_back(fromDirConfig + targetNameImportLib); - files.To.emplace_back(targetNameImportLib); - } + computeFilesToInstall( + files, this->ImportlinkMode, fromDirConfig, targetNames.ImportOutput, + targetNames.ImportLibrary, targetNames.ImportReal, GNUToMS); // An import library looks like a static library. files.Type = cmInstallType_STATIC_LIBRARY; @@ -318,66 +403,9 @@ cmInstallTargetGenerator::Files cmInstallTargetGenerator::GetFiles( files.From.emplace_back(std::move(from1)); files.To.emplace_back(std::move(to1)); } else { - bool haveNamelink = false; - - // Library link name. - std::string fromName = fromDirConfig + targetNames.Output; - std::string toName = targetNames.Output; - - // Library interface name. - std::string fromSOName; - std::string toSOName; - if (targetNames.SharedObject != targetNames.Output) { - haveNamelink = true; - fromSOName = fromDirConfig + targetNames.SharedObject; - toSOName = targetNames.SharedObject; - } - - // Library implementation name. - std::string fromRealName; - std::string toRealName; - if (targetNames.Real != targetNames.Output && - targetNames.Real != targetNames.SharedObject) { - haveNamelink = true; - fromRealName = fromDirConfig + targetNames.Real; - toRealName = targetNames.Real; - } - - // Add the names based on the current namelink mode. - if (haveNamelink) { - files.NamelinkMode = this->NamelinkMode; - // With a namelink we need to check the mode. - if (this->NamelinkMode == NamelinkModeOnly) { - // Install the namelink only. - files.From.emplace_back(fromName); - files.To.emplace_back(toName); - } else { - // Install the real file if it has its own name. - if (!fromRealName.empty()) { - files.From.emplace_back(fromRealName); - files.To.emplace_back(toRealName); - } - - // Install the soname link if it has its own name. - if (!fromSOName.empty()) { - files.From.emplace_back(fromSOName); - files.To.emplace_back(toSOName); - } - - // Install the namelink if it is not to be skipped. - if (this->NamelinkMode != NamelinkModeSkip) { - files.From.emplace_back(fromName); - files.To.emplace_back(toName); - } - } - } else { - // Without a namelink there will be only one file. Install it - // if this is not a namelink-only rule. - if (this->NamelinkMode != NamelinkModeOnly) { - files.From.emplace_back(fromName); - files.To.emplace_back(toName); - } - } + computeFilesToInstall(files, this->NamelinkMode, fromDirConfig, + targetNames.Output, targetNames.SharedObject, + targetNames.Real); } } @@ -425,6 +453,12 @@ std::string cmInstallTargetGenerator::GetInstallFilename( "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) { fname = targetNames.ImportLibrary; } + } else if (nameType == NameImplibReal) { + // Use the import library name. + if (!target->GetImplibGNUtoMS(config, targetNames.ImportReal, fname, + "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) { + fname = targetNames.ImportReal; + } } else if (nameType == NameReal) { // Use the canonical name. fname = targetNames.Real; @@ -434,11 +468,14 @@ std::string cmInstallTargetGenerator::GetInstallFilename( } } else { cmGeneratorTarget::Names targetNames = target->GetLibraryNames(config); - if (nameType == NameImplib) { + if (nameType == NameImplib || nameType == NameImplibReal) { + const auto& importName = nameType == NameImplib + ? targetNames.ImportLibrary + : targetNames.ImportReal; // Use the import library name. - if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname, + if (!target->GetImplibGNUtoMS(config, importName, fname, "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) { - fname = targetNames.ImportLibrary; + fname = importName; } } else if (nameType == NameSO) { // Use the soname. @@ -784,7 +821,7 @@ void cmInstallTargetGenerator::AddStripRule(std::ostream& os, Indent indent, } // Don't handle OSX Bundles. - if (this->Target->Target->GetMakefile()->IsOn("APPLE") && + if (this->Target->IsApple() && this->Target->GetPropertyAsBool("MACOSX_BUNDLE")) { return; } @@ -796,7 +833,7 @@ void cmInstallTargetGenerator::AddStripRule(std::ostream& os, Indent indent, std::string stripArgs; // macOS 'strip' is picky, executables need '-u -r' and dylibs need '-x'. - if (this->Target->Target->GetMakefile()->IsOn("APPLE")) { + if (this->Target->IsApple()) { if (this->Target->GetType() == cmStateEnums::SHARED_LIBRARY || this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) { stripArgs = "-x "; @@ -822,7 +859,7 @@ void cmInstallTargetGenerator::AddRanlibRule(std::ostream& os, Indent indent, // Perform post-installation processing on the file depending // on its type. - if (!this->Target->Target->GetMakefile()->IsOn("APPLE")) { + if (!this->Target->IsApple()) { return; } diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index 3fc4b59..2f41163 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -39,6 +39,10 @@ public: NamelinkModeSkip }; void SetNamelinkMode(NamelinkModeType mode) { this->NamelinkMode = mode; } + void SetImportlinkMode(NamelinkModeType mode) + { + this->ImportlinkMode = mode; + } std::string GetInstallFilename(const std::string& config) const; @@ -50,7 +54,8 @@ public: NameNormal, NameImplib, NameSO, - NameReal + NameReal, + NameImplibReal }; static std::string GetInstallFilename(const cmGeneratorTarget* target, @@ -121,6 +126,7 @@ protected: cmGeneratorTarget* Target = nullptr; std::string const FilePermissions; NamelinkModeType NamelinkMode; + NamelinkModeType ImportlinkMode; bool const ImportLibrary; bool const Optional; }; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index c2138ee..bd7eb3f 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -85,6 +85,7 @@ static auto ruleReplaceVars = { "CMAKE_${LANG}_COMPILER", "CMAKE_RANLIB", "CMAKE_LINKER", "CMAKE_MT", + "CMAKE_TAPI", "CMAKE_CUDA_HOST_COMPILER", "CMAKE_CUDA_HOST_LINK_LAUNCHER", "CMAKE_CL_SHOWINCLUDES_PREFIX" }; @@ -134,6 +135,13 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile) this->LinkerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT"); } + // OSX SYSROOT can be required by some tools, like tapi + { + cmValue osxSysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT"); + this->VariableMappings["CMAKE_OSX_SYSROOT"] = + osxSysroot.IsEmpty() ? "/" : this->EscapeForShell(*osxSysroot, true); + } + if (cmValue appleArchSysroots = this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) { std::string const& appleArchs = @@ -1644,7 +1652,7 @@ static std::string GetFrameworkFlags(const std::string& lang, cmLocalGenerator* lg = target->GetLocalGenerator(); cmMakefile* mf = lg->GetMakefile(); - if (!mf->IsOn("APPLE")) { + if (!target->IsApple()) { return std::string(); } @@ -1818,7 +1826,7 @@ std::string cmLocalGenerator::GetLinkLibsCMP0065( // OLD behavior is to always add the flags, except on AIX where // we compute symbol exports if ENABLE_EXPORTS is on. add_shlib_flags = - !(tgt.Target->IsAIX() && tgt.GetPropertyAsBool("ENABLE_EXPORTS")); + !(tgt.IsAIX() && tgt.GetPropertyAsBool("ENABLE_EXPORTS")); break; case cmPolicies::REQUIRED_IF_USED: case cmPolicies::REQUIRED_ALWAYS: @@ -1830,7 +1838,7 @@ std::string cmLocalGenerator::GetLinkLibsCMP0065( // NEW behavior is to only add the flags if ENABLE_EXPORTS is on, // except on AIX where we compute symbol exports. add_shlib_flags = - !tgt.Target->IsAIX() && tgt.GetPropertyAsBool("ENABLE_EXPORTS"); + !tgt.IsAIX() && tgt.GetPropertyAsBool("ENABLE_EXPORTS"); break; } @@ -1864,7 +1872,7 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, const std::string& filterArch) { // Only add Apple specific flags on Apple platforms - if (this->Makefile->IsOn("APPLE") && this->EmitUniversalBinaryFlags) { + if (target->IsApple() && this->EmitUniversalBinaryFlags) { std::vector<std::string> archs; target->GetAppleArchs(config, archs); if (!archs.empty() && diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 2fc2974..3fcc7f7 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -1229,7 +1229,7 @@ void cmMakefile::AddCustomCommandOldStyle( // Each output must get its own copy of this rule. cmsys::RegularExpression sourceFiles( - "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|mpp|ixx|cppm|cu|m|mm|" + "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|mpp|ixx|cppm|ccm|cxxm|c\\+\\+m|cu|m|mm|" "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|" "hm|hpp|hxx|in|txx|inl)$"); @@ -2493,6 +2493,11 @@ bool cmMakefile::PlatformIsAppleEmbedded() const return this->GetAppleSDKType() != AppleSDK::MacOS; } +bool cmMakefile::PlatformSupportsAppleTextStubs() const +{ + return this->IsOn("APPLE") && this->IsSet("CMAKE_TAPI"); +} + const char* cmMakefile::GetSONameFlag(const std::string& language) const { std::string name = "CMAKE_SHARED_LIBRARY_SONAME"; diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 3cf6e61..6f04937 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -562,6 +562,10 @@ public: /** Return whether the target platform is Apple iOS. */ bool PlatformIsAppleEmbedded() const; + /** Return whether the target platform supports generation of text base stubs + (.tbd file) describing exports (Apple specific). */ + bool PlatformSupportsAppleTextStubs() const; + /** Retrieve soname flag for the specified language if supported */ const char* GetSONameFlag(const std::string& language) const; diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 41daa5a..1960073 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -185,14 +185,15 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule( std::string linkLibs; this->CreateLinkLibs( linkLineComputer.get(), linkLibs, useResponseFileForLibs, depends, - cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); + linkLanguage, cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); // Construct object file lists that may be needed to expand the // rule. std::string buildObjs; this->CreateObjectLists( useLinkScript, false, useResponseFileForObjects, buildObjs, depends, - false, cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); + false, linkLanguage, + cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); cmRulePlaceholderExpander::RuleVariables vars; std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); @@ -503,13 +504,13 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Collect up flags to link in needed libraries. std::string linkLibs; this->CreateLinkLibs(linkLineComputer.get(), linkLibs, - useResponseFileForLibs, depends); + useResponseFileForLibs, depends, linkLanguage); // Construct object file lists that may be needed to expand the // rule. std::string buildObjs; this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects, - buildObjs, depends, useWatcomQuote); + buildObjs, depends, useWatcomQuote, linkLanguage); if (!this->DeviceLinkObject.empty()) { buildObjs += " " + this->LocalGenerator->ConvertToOutputFormat( diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index cb567ff..3e4a08e 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -327,14 +327,14 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules( this->CreateLinkLibs( linkLineComputer.get(), linkLibs, useResponseFileForLibs, depends, - cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); + linkLanguage, cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); // Construct object file lists that may be needed to expand the // rule. std::string buildObjs; this->CreateObjectLists( useLinkScript, false, // useArchiveRules - useResponseFileForObjects, buildObjs, depends, false, + useResponseFileForObjects, buildObjs, depends, false, linkLanguage, cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); @@ -465,9 +465,20 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( std::string outpathImp; if (this->GeneratorTarget->IsFrameworkOnApple()) { outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName()); + cmOSXBundleGenerator::SkipParts bundleSkipParts; + if (this->GeneratorTarget->HasImportLibrary(this->GetConfigName())) { + bundleSkipParts.TextStubs = false; + } this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output, - outpath, this->GetConfigName()); + outpath, this->GetConfigName(), + bundleSkipParts); outpath += '/'; + if (!this->TargetNames.ImportLibrary.empty()) { + outpathImp = this->GeneratorTarget->GetDirectory( + this->GetConfigName(), cmStateEnums::ImportLibraryArtifact); + cmSystemTools::MakeDirectory(outpathImp); + outpathImp += '/'; + } } else if (this->GeneratorTarget->IsCFBundleOnApple()) { outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName()); this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output, outpath, @@ -679,11 +690,12 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( } // Expand the rule variables. + std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( + this->LocalGenerator->CreateRulePlaceholderExpander()); + bool useWatcomQuote = + this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE"); std::vector<std::string> real_link_commands; { - bool useWatcomQuote = - this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE"); - // Set path conversion for link script shells. this->LocalGenerator->SetLinkScriptShell(useLinkScript); @@ -700,7 +712,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( linkLineComputer->SetRelink(relink); this->CreateLinkLibs(linkLineComputer.get(), linkLibs, - useResponseFileForLibs, depends); + useResponseFileForLibs, depends, linkLanguage); } // Construct object file lists that may be needed to expand the @@ -708,7 +720,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( std::string buildObjs; this->CreateObjectLists(useLinkScript, useArchiveRules, useResponseFileForObjects, buildObjs, depends, - useWatcomQuote); + useWatcomQuote, linkLanguage); if (!this->DeviceLinkObject.empty()) { buildObjs += " " + this->LocalGenerator->ConvertToOutputFormat( @@ -816,8 +828,6 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( launcher = cmStrCat(val, ' '); } - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->LocalGenerator->CreateRulePlaceholderExpander()); // Construct the main link rule and expand placeholders. rulePlaceholderExpander->SetTargetImpLib(targetOutPathImport); if (useArchiveRules) { @@ -950,6 +960,86 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends, commands, false); + // Add rule to generate text-based stubs, if required + if (this->GeneratorTarget->IsApple() && + this->GeneratorTarget->HasImportLibrary(this->GetConfigName())) { + auto genStubsRule = + this->Makefile->GetDefinition("CMAKE_CREATE_TEXT_STUBS"); + auto genStubs_commands = cmExpandedList(genStubsRule); + + std::string TBDFullPath = + cmStrCat(outpathImp, this->TargetNames.ImportOutput); + std::string TBDFullPathReal = + cmStrCat(outpathImp, this->TargetNames.ImportReal); + std::string TBDFullPathSO = + cmStrCat(outpathImp, this->TargetNames.ImportLibrary); + + // Expand placeholders. + cmRulePlaceholderExpander::RuleVariables vars; + std::string target = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal), + cmOutputConverter::SHELL, useWatcomQuote); + vars.Target = target.c_str(); + std::string TBDOutPathReal = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPathReal), + cmOutputConverter::SHELL, useWatcomQuote); + rulePlaceholderExpander->SetTargetImpLib(TBDOutPathReal); + for (std::string& command : genStubs_commands) { + rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, + command, vars); + } + outputs.clear(); + outputs.push_back(TBDFullPathReal); + if (this->TargetNames.ImportLibrary != this->TargetNames.ImportReal) { + outputs.push_back(TBDFullPathSO); + } + if (this->TargetNames.ImportOutput != this->TargetNames.ImportLibrary && + this->TargetNames.ImportOutput != this->TargetNames.ImportReal) { + outputs.push_back(TBDFullPath); + } + this->ExtraFiles.insert(TBDFullPath); + + depends.clear(); + depends.push_back(targetFullPathReal); + + // Add a rule to create necessary symlinks for the library. + // Frameworks are handled by cmOSXBundleGenerator. + if (TBDFullPath != TBDFullPathReal && + !this->GeneratorTarget->IsFrameworkOnApple()) { + auto TBDOutPathSO = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPathSO), + cmOutputConverter::SHELL, useWatcomQuote); + auto TBDOutPath = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPath), + cmOutputConverter::SHELL, useWatcomQuote); + + std::string symlink = + cmStrCat("$(CMAKE_COMMAND) -E cmake_symlink_library ", TBDOutPathReal, + ' ', TBDOutPathSO, ' ', TBDOutPath); + commands1.push_back(std::move(symlink)); + this->LocalGenerator->CreateCDCommand( + commands1, this->Makefile->GetCurrentBinaryDirectory(), + this->LocalGenerator->GetBinaryDirectory()); + cm::append(genStubs_commands, commands1); + commands1.clear(); + } + + this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends, + genStubs_commands, false); + + // clean actions for apple specific outputs + // clean actions for ImportLibrary are already specified + if (this->TargetNames.ImportReal != this->TargetNames.ImportLibrary) { + libCleanFiles.insert( + this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPathReal)); + } + if (this->TargetNames.ImportOutput != this->TargetNames.ImportReal && + this->TargetNames.ImportOutput != this->TargetNames.ImportLibrary) { + libCleanFiles.insert( + this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPath)); + } + } + // Write the main driver rule to build everything in this target. this->WriteTargetDriverRule(targetFullPath, relink); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 915a412..2ead739 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -2189,16 +2189,16 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForLibraries( std::string cmMakefileTargetGenerator::CreateResponseFile( const std::string& name, std::string const& options, - std::vector<std::string>& makefile_depends) + std::vector<std::string>& makefile_depends, std::string const& language) { // FIXME: Find a better way to determine the response file encoding, // perhaps using tool-specific platform information variables. // For now, use the makefile encoding as a heuristic. codecvt::Encoding responseEncoding = this->GlobalGenerator->GetMakefileEncoding(); - // Non-MSVC tooling may not understand a BOM. + // Non-MSVC tooling doesn't understand BOM encoded files. if (responseEncoding == codecvt::UTF8_WITH_BOM && - !this->Makefile->IsOn("MSVC")) { + (language == "CUDA" || !this->Makefile->IsOn("MSVC"))) { responseEncoding = codecvt::UTF8; } @@ -2235,7 +2235,7 @@ cmMakefileTargetGenerator::CreateLinkLineComputer( void cmMakefileTargetGenerator::CreateLinkLibs( cmLinkLineComputer* linkLineComputer, std::string& linkLibs, bool useResponseFile, std::vector<std::string>& makefile_depends, - ResponseFlagFor responseMode) + std::string const& linkLanguage, ResponseFlagFor responseMode) { std::string frameworkPath; std::string linkPath; @@ -2253,8 +2253,9 @@ void cmMakefileTargetGenerator::CreateLinkLibs( // Create this response file. std::string responseFileName = (responseMode == Link) ? "linkLibs.rsp" : "deviceLinkLibs.rsp"; - std::string link_rsp = - this->CreateResponseFile(responseFileName, linkLibs, makefile_depends); + std::string responseLang = (responseMode == Link) ? linkLanguage : "CUDA"; + std::string link_rsp = this->CreateResponseFile( + responseFileName, linkLibs, makefile_depends, responseLang); // Reference the response file. linkLibs = cmStrCat(responseFlag, @@ -2266,7 +2267,8 @@ void cmMakefileTargetGenerator::CreateLinkLibs( void cmMakefileTargetGenerator::CreateObjectLists( bool useLinkScript, bool useArchiveRules, bool useResponseFile, std::string& buildObjs, std::vector<std::string>& makefile_depends, - bool useWatcomQuote, ResponseFlagFor responseMode) + bool useWatcomQuote, std::string const& linkLanguage, + ResponseFlagFor responseMode) { std::string variableName; std::string variableNameExternal; @@ -2295,7 +2297,7 @@ void cmMakefileTargetGenerator::CreateObjectLists( // Create this response file. std::string objects_rsp = this->CreateResponseFile( - responseFileName, object_strings[i], makefile_depends); + responseFileName, object_strings[i], makefile_depends, linkLanguage); // Separate from previous response file references. buildObjs += sep; @@ -2347,8 +2349,8 @@ void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags, } std::string name = cmStrCat("includes_", lang, ".rsp"); std::string arg = std::move(responseFlag) + - this->CreateResponseFile(name, includeFlags, - this->FlagFileDepends[lang]); + this->CreateResponseFile(name, includeFlags, this->FlagFileDepends[lang], + lang); this->LocalGenerator->AppendFlags(flags, arg); } else { this->LocalGenerator->AppendFlags(flags, includeFlags); diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 5d614fe..98c3a0e 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -160,7 +160,8 @@ protected: response file name. */ std::string CreateResponseFile(const std::string& name, std::string const& options, - std::vector<std::string>& makefile_depends); + std::vector<std::string>& makefile_depends, + std::string const& language); bool CheckUseResponseFileForObjects(std::string const& l) const; bool CheckUseResponseFileForLibraries(std::string const& l) const; @@ -175,13 +176,14 @@ protected: void CreateLinkLibs(cmLinkLineComputer* linkLineComputer, std::string& linkLibs, bool useResponseFile, std::vector<std::string>& makefile_depends, + std::string const& linkLanguage, ResponseFlagFor responseMode = ResponseFlagFor::Link); /** Create lists of object files for linking and cleaning. */ void CreateObjectLists(bool useLinkScript, bool useArchiveRules, bool useResponseFile, std::string& buildObjs, std::vector<std::string>& makefile_depends, - bool useWatcomQuote, + bool useWatcomQuote, std::string const& linkLanguage, ResponseFlagFor responseMode = ResponseFlagFor::Link); /** Add commands for generate def files */ diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 45a4dda..4d68460 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -204,6 +204,15 @@ std::string cmNinjaNormalTargetGenerator::LanguageLinkerCudaFatbinaryRule( '_', config); } +std::string cmNinjaNormalTargetGenerator::TextStubsGeneratorRule( + const std::string& config) const +{ + return cmStrCat( + "TEXT_STUBS_GENERATOR__", + cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), + '_', config); +} + struct cmNinjaRemoveNoOpCommands { bool operator()(std::string const& cmd) @@ -527,6 +536,45 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, this->GetGlobalGenerator()->AddRule(rule); } } + + if (this->GetGeneratorTarget()->IsApple() && + this->GetGeneratorTarget()->HasImportLibrary(config)) { + cmNinjaRule rule(this->TextStubsGeneratorRule(config)); + rule.Comment = cmStrCat("Rule for generating text-based stubs for ", + this->GetVisibleTypeName(), '.'); + rule.Description = "Creating text-based stubs $out"; + + std::string cmd = + this->GetMakefile()->GetDefinition("CMAKE_CREATE_TEXT_STUBS"); + std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( + this->GetLocalGenerator()->CreateRulePlaceholderExpander()); + cmRulePlaceholderExpander::RuleVariables vars; + vars.Target = "$in"; + rulePlaceholderExpander->SetTargetImpLib("$out"); + rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), + cmd, vars); + + rule.Command = + this->GetLocalGenerator()->BuildCommandLine({ cmd }, config, config); + this->GetGlobalGenerator()->AddRule(rule); + + if (tgtNames.ImportOutput != tgtNames.ImportReal && + !this->GetGeneratorTarget()->IsFrameworkOnApple()) { + cmNinjaRule slRule("CMAKE_SYMLINK_IMPORT_LIBRARY"); + { + std::string cmakeCommand = + this->GetLocalGenerator()->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); + std::string slCmd = + cmStrCat(cmakeCommand, " -E cmake_symlink_library $in $SONAME $out"); + slRule.Command = this->GetLocalGenerator()->BuildCommandLine( + { slCmd }, config, config); + } + slRule.Description = "Creating import library symlink $out"; + slRule.Comment = "Rule for creating import library symlink."; + this->GetGlobalGenerator()->AddRule(slRule); + } + } } std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd() @@ -1030,9 +1078,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( // the current configuration has a postfix. The non-postfix configuration // Info.plist can be used by all the other configurations. if (!postFix.empty()) { - bundleSkipParts.infoPlist = true; + bundleSkipParts.InfoPlist = true; } } + if (gt->HasImportLibrary(config)) { + bundleSkipParts.TextStubs = false; + } this->OSXBundleGenerator->CreateFramework( tgtNames.Output, gt->GetDirectory(config), config, bundleSkipParts); @@ -1214,7 +1265,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( cmGlobalNinjaGenerator::CCOutputs byproducts(this->GetGlobalGenerator()); - if (!tgtNames.ImportLibrary.empty()) { + if (!gt->IsApple() && !tgtNames.ImportLibrary.empty()) { const std::string impLibPath = localGen.ConvertToOutputFormat( targetOutputImplib, cmOutputConverter::SHELL); vars["TARGET_IMPLIB"] = impLibPath; @@ -1471,6 +1522,55 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( // Add aliases for the file name and the target name. globalGen->AddTargetAlias(tgtNames.Output, gt, config); globalGen->AddTargetAlias(this->GetTargetName(), gt, config); + + if (this->GetGeneratorTarget()->IsApple() && + this->GetGeneratorTarget()->HasImportLibrary(config)) { + auto dirTBD = + gt->GetDirectory(config, cmStateEnums::ImportLibraryArtifact); + auto targetTBD = + this->ConvertToNinjaPath(cmStrCat(dirTBD, '/', tgtNames.ImportReal)); + this->EnsureParentDirectoryExists(targetTBD); + cmNinjaBuild build(this->TextStubsGeneratorRule(config)); + build.Comment = cmStrCat("Generate the text-based stubs file ", targetTBD); + build.Outputs.push_back(targetTBD); + build.ExplicitDeps.push_back(targetOutputReal); + globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build); + + if (tgtNames.ImportOutput != tgtNames.ImportReal && + !this->GetGeneratorTarget()->IsFrameworkOnApple()) { + auto outputTBD = + this->ConvertToNinjaPath(cmStrCat(dirTBD, '/', tgtNames.ImportOutput)); + std::string const soNameTBD = this->ConvertToNinjaPath( + cmStrCat(dirTBD, '/', tgtNames.ImportLibrary)); + + cmNinjaBuild slBuild("CMAKE_SYMLINK_IMPORT_LIBRARY"); + slBuild.Comment = cmStrCat("Create import library symlink ", outputTBD); + cmNinjaVars slVars; + + // If one link has to be created. + if (targetTBD == soNameTBD || outputTBD == soNameTBD) { + slVars["SONAME"] = this->GetLocalGenerator()->ConvertToOutputFormat( + soNameTBD, cmOutputConverter::SHELL); + } else { + slVars["SONAME"].clear(); + slBuild.Outputs.push_back(soNameTBD); + if (firstForConfig) { + globalGen->GetByproductsForCleanTarget(config).push_back(soNameTBD); + } + } + slBuild.Outputs.push_back(outputTBD); + if (firstForConfig) { + globalGen->GetByproductsForCleanTarget(config).push_back(outputTBD); + } + slBuild.ExplicitDeps.push_back(targetTBD); + slBuild.Variables = std::move(slVars); + + globalGen->WriteBuild(this->GetImplFileStream(fileConfig), slBuild); + } + + // Add alias for the import file name + globalGen->AddTargetAlias(tgtNames.ImportOutput, gt, config); + } } void cmNinjaNormalTargetGenerator::WriteObjectLibStatement( diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h index 30127fe..85f42a4 100644 --- a/Source/cmNinjaNormalTargetGenerator.h +++ b/Source/cmNinjaNormalTargetGenerator.h @@ -25,6 +25,7 @@ private: std::string LanguageLinkerCudaDeviceCompileRule( const std::string& config) const; std::string LanguageLinkerCudaFatbinaryRule(const std::string& config) const; + std::string TextStubsGeneratorRule(const std::string& config) const; const char* GetVisibleTypeName() const; void WriteLanguagesRules(const std::string& config); diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx index 674735b..4301f05 100644 --- a/Source/cmOSXBundleGenerator.cxx +++ b/Source/cmOSXBundleGenerator.cxx @@ -11,6 +11,7 @@ #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" +#include "cmValue.h" class cmSourceFile; @@ -77,7 +78,7 @@ void cmOSXBundleGenerator::CreateFramework( std::string frameworkVersion = this->GT->GetFrameworkVersion(); std::string name = cmSystemTools::GetFilenameName(targetName); - if (!skipParts.infoPlist) { + if (!skipParts.InfoPlist) { // Configure the Info.plist file std::string plist = newoutpath; if (!this->Makefile->PlatformIsAppleEmbedded()) { @@ -120,6 +121,17 @@ void cmOSXBundleGenerator::CreateFramework( cmSystemTools::CreateSymlink(oldName, newName); this->Makefile->AddCMakeOutputFile(newName); + if (!skipParts.TextStubs) { + // foo.tbd -> Versions/Current/foo.tbd + cmValue tbdSuffix = + this->Makefile->GetDefinition("CMAKE_APPLE_IMPORT_FILE_SUFFIX"); + oldName = cmStrCat("Versions/Current/", name, tbdSuffix); + newName = cmStrCat(contentdir, name, tbdSuffix); + cmSystemTools::RemoveFile(newName); + cmSystemTools::CreateSymlink(oldName, newName); + this->Makefile->AddCMakeOutputFile(newName); + } + // Resources -> Versions/Current/Resources if (this->MacContentFolders->find("Resources") != this->MacContentFolders->end()) { diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h index c33b087..38453fd 100644 --- a/Source/cmOSXBundleGenerator.h +++ b/Source/cmOSXBundleGenerator.h @@ -20,11 +20,10 @@ public: struct SkipParts { - SkipParts() - : infoPlist(false) - { - } - bool infoPlist; // NOLINT(modernize-use-default-member-init) + SkipParts() {} // NOLINT(modernize-use-equals-default) + + bool InfoPlist = false; + bool TextStubs = true; }; // create an app bundle at a given root, and return @@ -35,7 +34,7 @@ public: // create a framework at a given root void CreateFramework(const std::string& targetName, const std::string& root, const std::string& config, - const SkipParts& skipParts = SkipParts()); + const SkipParts& skipParts = SkipParts{}); // create a cf bundle at a given root void CreateCFBundle(const std::string& targetName, const std::string& root, diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 830e14b..52993b8 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -439,6 +439,11 @@ class cmMakefile; "find_package uses upper-case <PACKAGENAME>_ROOT variables.", 3, 27, \ 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0145, "The Dart and FindDart modules are removed.", 3, \ + 27, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0146, "The FindCUDA module is removed.", 3, 27, 0, \ + cmPolicies::WARN) \ + SELECT(POLICY, CMP0147, \ + "Visual Studio generators build custom commands in parallel.", 3, \ 27, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) @@ -479,7 +484,9 @@ class cmMakefile; F(CMP0131) \ F(CMP0142) -#define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F) F(CMP0116) +#define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F) \ + F(CMP0116) \ + F(CMP0147) /** \class cmPolicies * \brief Handles changes in CMake behavior and policies diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx index fa9d4cc..5ff7009 100644 --- a/Source/cmRST.cxx +++ b/Source/cmRST.cxx @@ -20,8 +20,8 @@ cmRST::cmRST(std::ostream& os, std::string docroot) : OS(os) , DocRoot(std::move(docroot)) , CMakeDirective("^.. (cmake:)?(" - "command|envvar|genex|variable" - ")::[ \t]+([^ \t\n]+)$") + "command|envvar|genex|signature|variable" + ")::") , CMakeModuleDirective("^.. cmake-module::[ \t]+([^ \t\n]+)$") , ParsedLiteralDirective("^.. parsed-literal::[ \t]*(.*)$") , CodeBlockDirective("^.. code-block::[ \t]*(.*)$") @@ -126,27 +126,27 @@ void cmRST::Reset() if (!this->MarkupLines.empty()) { cmRST::UnindentLines(this->MarkupLines); } - switch (this->Directive) { - case DirectiveNone: + switch (this->DirectiveType) { + case Directive::None: break; - case DirectiveParsedLiteral: + case Directive::ParsedLiteral: this->ProcessDirectiveParsedLiteral(); break; - case DirectiveLiteralBlock: + case Directive::LiteralBlock: this->ProcessDirectiveLiteralBlock(); break; - case DirectiveCodeBlock: + case Directive::CodeBlock: this->ProcessDirectiveCodeBlock(); break; - case DirectiveReplace: + case Directive::Replace: this->ProcessDirectiveReplace(); break; - case DirectiveTocTree: + case Directive::TocTree: this->ProcessDirectiveTocTree(); break; } - this->Markup = MarkupNone; - this->Directive = DirectiveNone; + this->MarkupType = Markup::None; + this->DirectiveType = Directive::None; this->MarkupLines.clear(); } @@ -160,9 +160,9 @@ void cmRST::ProcessLine(std::string const& line) (line.size() >= 3 && line[0] == '.' && line[1] == '.' && isspace(line[2]))) { this->Reset(); - this->Markup = - (line.find_first_not_of(" \t", 2) == std::string::npos ? MarkupEmpty - : MarkupNormal); + this->MarkupType = + (line.find_first_not_of(" \t", 2) == std::string::npos ? Markup::Empty + : Markup::Normal); // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 // NOLINTNEXTLINE(bugprone-branch-clone) if (this->CMakeDirective.find(line)) { @@ -171,33 +171,33 @@ void cmRST::ProcessLine(std::string const& line) } else if (this->CMakeModuleDirective.find(line)) { // Process cmake-module directive: scan .cmake file comments. std::string file = this->CMakeModuleDirective.match(1); - if (file.empty() || !this->ProcessInclude(file, IncludeModule)) { + if (file.empty() || !this->ProcessInclude(file, Include::Module)) { this->NormalLine(line); } } else if (this->ParsedLiteralDirective.find(line)) { // Record the literal lines to output after whole block. - this->Directive = DirectiveParsedLiteral; + this->DirectiveType = Directive::ParsedLiteral; this->MarkupLines.push_back(this->ParsedLiteralDirective.match(1)); } else if (this->CodeBlockDirective.find(line)) { // Record the literal lines to output after whole block. // Ignore the language spec and record the opening line as blank. - this->Directive = DirectiveCodeBlock; + this->DirectiveType = Directive::CodeBlock; this->MarkupLines.emplace_back(); } else if (this->ReplaceDirective.find(line)) { // Record the replace directive content. - this->Directive = DirectiveReplace; + this->DirectiveType = Directive::Replace; this->ReplaceName = this->ReplaceDirective.match(1); this->MarkupLines.push_back(this->ReplaceDirective.match(2)); } else if (this->IncludeDirective.find(line)) { // Process the include directive or output the directive and its // content normally if it fails. std::string file = this->IncludeDirective.match(1); - if (file.empty() || !this->ProcessInclude(file, IncludeNormal)) { + if (file.empty() || !this->ProcessInclude(file, Include::Normal)) { this->NormalLine(line); } } else if (this->TocTreeDirective.find(line)) { // Record the toctree entries to process after whole block. - this->Directive = DirectiveTocTree; + this->DirectiveType = Directive::TocTree; this->MarkupLines.push_back(this->TocTreeDirective.match(1)); } else if (this->ProductionListDirective.find(line)) { // Output productionlist directives and their content normally. @@ -211,14 +211,15 @@ void cmRST::ProcessLine(std::string const& line) this->NormalLine(line); } } - // An explicit markup start followed nothing but whitespace and a + // An explicit markup start followed by nothing but whitespace and a // blank line does not consume any indented text following. - else if (this->Markup == MarkupEmpty && line.empty()) { + else if (this->MarkupType == Markup::Empty && line.empty()) { this->NormalLine(line); } // Indented lines following an explicit markup start are explicit markup. - else if (this->Markup && (line.empty() || isspace(line[0]))) { - this->Markup = MarkupNormal; + else if (this->MarkupType != Markup::None && + (line.empty() || isspace(line[0]))) { + this->MarkupType = Markup::Normal; // Record markup lines if the start line was recorded. if (!this->MarkupLines.empty()) { this->MarkupLines.push_back(line); @@ -227,8 +228,8 @@ void cmRST::ProcessLine(std::string const& line) // A blank line following a paragraph ending in "::" starts a literal block. else if (lastLineEndedInColonColon && line.empty()) { // Record the literal lines to output after whole block. - this->Markup = MarkupNormal; - this->Directive = DirectiveLiteralBlock; + this->MarkupType = Markup::Normal; + this->DirectiveType = Directive::LiteralBlock; this->MarkupLines.emplace_back(); this->OutputLine("", false); } @@ -354,14 +355,14 @@ void cmRST::OutputMarkupLines(bool inlineMarkup) this->OutputLinePending = true; } -bool cmRST::ProcessInclude(std::string file, IncludeType type) +bool cmRST::ProcessInclude(std::string file, Include type) { bool found = false; if (this->IncludeDepth < 10) { cmRST r(this->OS, this->DocRoot); r.IncludeDepth = this->IncludeDepth + 1; r.OutputLinePending = this->OutputLinePending; - if (type != IncludeTocTree) { + if (type != Include::TocTree) { r.Replace = this->Replace; } if (file[0] == '/') { @@ -369,8 +370,8 @@ bool cmRST::ProcessInclude(std::string file, IncludeType type) } else { file = this->DocDir + "/" + file; } - found = r.ProcessFile(file, type == IncludeModule); - if (type != IncludeTocTree) { + found = r.ProcessFile(file, type == Include::Module); + if (type != Include::TocTree) { this->Replace = r.Replace; } this->OutputLinePending = r.OutputLinePending; @@ -408,9 +409,9 @@ void cmRST::ProcessDirectiveTocTree() if (!line.empty() && line[0] != ':') { if (this->TocTreeLink.find(line)) { std::string const& link = this->TocTreeLink.match(1); - this->ProcessInclude(link + ".rst", IncludeTocTree); + this->ProcessInclude(link + ".rst", Include::TocTree); } else { - this->ProcessInclude(line + ".rst", IncludeTocTree); + this->ProcessInclude(line + ".rst", Include::TocTree); } } } diff --git a/Source/cmRST.h b/Source/cmRST.h index ea4ef22..65a8a71 100644 --- a/Source/cmRST.h +++ b/Source/cmRST.h @@ -29,26 +29,26 @@ public: bool ProcessFile(std::string const& fname, bool isModule = false); private: - enum IncludeType + enum class Include { - IncludeNormal, - IncludeModule, - IncludeTocTree + Normal, + Module, + TocTree }; - enum MarkupType + enum class Markup { - MarkupNone, - MarkupNormal, - MarkupEmpty + None, + Normal, + Empty }; - enum DirectiveType + enum class Directive { - DirectiveNone, - DirectiveParsedLiteral, - DirectiveLiteralBlock, - DirectiveCodeBlock, - DirectiveReplace, - DirectiveTocTree + None, + ParsedLiteral, + LiteralBlock, + CodeBlock, + Replace, + TocTree }; void ProcessRST(std::istream& is); @@ -59,7 +59,7 @@ private: void OutputLine(std::string const& line, bool inlineMarkup); std::string ReplaceSubstitutions(std::string const& line); void OutputMarkupLines(bool inlineMarkup); - bool ProcessInclude(std::string file, IncludeType type); + bool ProcessInclude(std::string file, Include type); void ProcessDirectiveParsedLiteral(); void ProcessDirectiveLiteralBlock(); void ProcessDirectiveCodeBlock(); @@ -72,8 +72,8 @@ private: int IncludeDepth = 0; bool OutputLinePending = false; bool LastLineEndedInColonColon = false; - MarkupType Markup = MarkupNone; - DirectiveType Directive = DirectiveNone; + Markup MarkupType = Markup::None; + Directive DirectiveType = Directive::None; cmsys::RegularExpression CMakeDirective; cmsys::RegularExpression CMakeModuleDirective; cmsys::RegularExpression ParsedLiteralDirective; diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h index c1c5201..9308af4 100644 --- a/Source/cmSourceFile.h +++ b/Source/cmSourceFile.h @@ -183,8 +183,8 @@ private: #define CM_HEADER_REGEX "\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$" #define CM_SOURCE_REGEX \ - "\\.(C|F|M|c|c\\+\\+|cc|cpp|mpp|cxx|ixx|cppm|cu|f|f90|for|fpp|ftn|m|mm|" \ - "rc|def|r|odl|idl|hpj|bat)$" + "\\.(C|F|M|c|c\\+\\+|cc|cpp|mpp|cxx|ixx|cppm|ccm|cxxm|c\\+\\+m|cu" \ + "|f|f90|for|fpp|ftn|m|mm|rc|def|r|odl|idl|hpj|bat)$" #define CM_PCH_REGEX "cmake_pch(_[^.]+)?\\.(h|hxx)$" diff --git a/Source/cmState.h b/Source/cmState.h index 9a17b22..0a42df0 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -253,18 +253,6 @@ public: private: friend class cmake; - void AddCacheEntry(const std::string& key, const char* value, - const char* helpString, cmStateEnums::CacheEntryType type) - { - this->AddCacheEntry(key, - value ? cmValue(std::string(value)) : cmValue(nullptr), - helpString, type); - } - void AddCacheEntry(const std::string& key, const std::string& value, - const char* helpString, cmStateEnums::CacheEntryType type) - { - this->AddCacheEntry(key, cmValue(value), helpString, type); - } void AddCacheEntry(const std::string& key, cmValue value, const char* helpString, cmStateEnums::CacheEntryType type); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index fc13560..f06e26b 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -447,7 +447,7 @@ TargetProperty const StaticTargetProperties[] = { { "AUTORCC_OPTIONS"_s, IC::CanCompileSources }, // Linking properties - { "ENABLE_EXPORTS"_s, IC::ExecutableTarget }, + { "ENABLE_EXPORTS"_s, IC::TargetWithSymbolExports }, { "LINK_LIBRARIES_ONLY_TARGETS"_s, IC::NormalNonImportedTarget }, { "LINK_SEARCH_START_STATIC"_s, IC::CanCompileSources }, { "LINK_SEARCH_END_STATIC"_s, IC::CanCompileSources }, @@ -614,7 +614,6 @@ TargetProperty const StaticTargetProperties[] = { #undef COMMON_LANGUAGE_PROPERTIES #undef IC #undef R - } class cmTargetInternals @@ -631,6 +630,7 @@ public: bool HaveInstallRule; bool IsDLLPlatform; bool IsAIX; + bool IsApple; bool IsAndroid; bool BuildInterfaceIncludesAppended; bool PerConfig; @@ -917,6 +917,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->impl->HaveInstallRule = false; this->impl->IsDLLPlatform = false; this->impl->IsAIX = false; + this->impl->IsApple = false; this->impl->IsAndroid = false; this->impl->TargetVisibility = vis; this->impl->BuildInterfaceIncludesAppended = false; @@ -934,6 +935,9 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->impl->IsAIX = (systemName == "AIX" || systemName == "OS400"); } + // Check whether we are targeting Apple. + this->impl->IsApple = this->impl->Makefile->IsOn("APPLE"); + // Check whether we are targeting an Android platform. this->impl->IsAndroid = (this->impl->Makefile->GetSafeDefinition( "CMAKE_SYSTEM_NAME") == "Android"); @@ -1033,6 +1037,31 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, defKey += "CMAKE_"; auto initProperty = [this, mf, &defKey](const std::string& property, const char* default_value) { + // special init for ENABLE_EXPORTS + // For SHARED_LIBRARY, only CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS variable + // is used + // For EXECUTABLE, CMAKE_EXECUTABLE_ENABLE_EXPORTS or else + // CMAKE_ENABLE_EXPORTS variables are used + if (property == "ENABLE_EXPORTS"_s) { + // Replace everything after "CMAKE_" + defKey.replace( + defKey.begin() + 6, defKey.end(), + cmStrCat(this->impl->TargetType == cmStateEnums::EXECUTABLE + ? "EXECUTABLE" + : "SHARED_LIBRARY", + '_', property)); + if (cmValue value = mf->GetDefinition(defKey)) { + this->SetProperty(property, value); + return; + } + if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY) { + if (default_value) { + this->SetProperty(property, default_value); + } + return; + } + } + // Replace everything after "CMAKE_" defKey.replace(defKey.begin() + 6, defKey.end(), property); if (cmValue value = mf->GetDefinition(defKey)) { @@ -1207,18 +1236,22 @@ bool cmTarget::IsExecutableWithExports() const this->GetPropertyAsBool("ENABLE_EXPORTS")); } +bool cmTarget::IsSharedLibraryWithExports() const +{ + return (this->GetType() == cmStateEnums::SHARED_LIBRARY && + this->GetPropertyAsBool("ENABLE_EXPORTS")); +} + bool cmTarget::IsFrameworkOnApple() const { return ((this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::STATIC_LIBRARY) && - this->impl->Makefile->IsOn("APPLE") && - this->GetPropertyAsBool("FRAMEWORK")); + this->IsApple() && this->GetPropertyAsBool("FRAMEWORK")); } bool cmTarget::IsAppBundleOnApple() const { - return (this->GetType() == cmStateEnums::EXECUTABLE && - this->impl->Makefile->IsOn("APPLE") && + return (this->GetType() == cmStateEnums::EXECUTABLE && this->IsApple() && this->GetPropertyAsBool("MACOSX_BUNDLE")); } @@ -1783,7 +1816,6 @@ std::string ConvertToString<cmValue>(cmValue value) { return std::string(*value); } - } template <typename ValueType> @@ -2586,6 +2618,10 @@ bool cmTarget::IsAIX() const { return this->impl->IsAIX; } +bool cmTarget::IsApple() const +{ + return this->impl->IsApple; +} bool cmTarget::IsNormal() const { @@ -2685,7 +2721,8 @@ const char* cmTarget::GetSuffixVariableInternal( case cmStateEnums::RuntimeBinaryArtifact: return "CMAKE_SHARED_LIBRARY_SUFFIX"; case cmStateEnums::ImportLibraryArtifact: - return "CMAKE_IMPORT_LIBRARY_SUFFIX"; + return this->IsApple() ? "CMAKE_APPLE_IMPORT_FILE_SUFFIX" + : "CMAKE_IMPORT_LIBRARY_SUFFIX"; } break; case cmStateEnums::MODULE_LIBRARY: @@ -2726,7 +2763,8 @@ const char* cmTarget::GetPrefixVariableInternal( case cmStateEnums::RuntimeBinaryArtifact: return "CMAKE_SHARED_LIBRARY_PREFIX"; case cmStateEnums::ImportLibraryArtifact: - return "CMAKE_IMPORT_LIBRARY_PREFIX"; + return this->IsApple() ? "CMAKE_APPLE_IMPORT_FILE_PREFIX" + : "CMAKE_IMPORT_LIBRARY_PREFIX"; } break; case cmStateEnums::MODULE_LIBRARY: @@ -3001,7 +3039,9 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config, cmValue& loc, bool allowImp = (this->IsDLLPlatform() && (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->IsExecutableWithExports())) || - (this->IsAIX() && this->IsExecutableWithExports()); + (this->IsAIX() && this->IsExecutableWithExports()) || + (this->GetMakefile()->PlatformSupportsAppleTextStubs() && + this->IsSharedLibraryWithExports()); // If a mapping was found, check its configurations. for (auto mci = mappedConfigs.begin(); diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 95539fa..24f6fcd 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -205,6 +205,8 @@ public: //! Return whether or not we are targeting AIX. bool IsAIX() const; + //! Return whether or not we are targeting Apple. + bool IsApple() const; bool IsNormal() const; bool IsSynthetic() const; @@ -219,6 +221,10 @@ public: //! Return whether this target is an executable with symbol exports enabled. bool IsExecutableWithExports() const; + //! Return whether this target is a shared library with symbol exports + //! enabled. + bool IsSharedLibraryWithExports() const; + //! Return whether this target is a shared library Framework on Apple. bool IsFrameworkOnApple() const; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 652ca54..8926f9e 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -693,12 +693,12 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile( switch (this->ProjectType) { case VsProjectType::vcxproj: { + Elem(e0, "Import").Attribute("Project", VS10_CXX_DEFAULT_PROPS); std::string const& props = this->GlobalGenerator->GetPlatformToolsetVersionProps(); if (!props.empty()) { Elem(e0, "Import").Attribute("Project", props); } - Elem(e0, "Import").Attribute("Project", VS10_CXX_DEFAULT_PROPS); } break; case VsProjectType::csproj: Elem(e0, "Import") @@ -1810,13 +1810,15 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( this->WriteCustomRuleCSharp(e0, c, name, script, additional_inputs.str(), outputs.str(), comment, ccg); } else { - this->WriteCustomRuleCpp( - *spe2, c, script, additional_inputs.str(), outputs.str(), comment, ccg, - symbolic, - (command.GetUsesTerminal() || - (command.HasMainDependency() && source->GetIsGenerated())) - ? BuildInParallel::No - : BuildInParallel::Yes); + BuildInParallel buildInParallel = BuildInParallel::No; + if (command.GetCMP0147Status() == cmPolicies::NEW && + !command.GetUsesTerminal() && + !(command.HasMainDependency() && source->GetIsGenerated())) { + buildInParallel = BuildInParallel::Yes; + } + this->WriteCustomRuleCpp(*spe2, c, script, additional_inputs.str(), + outputs.str(), comment, ccg, symbolic, + buildInParallel); } } } diff --git a/Source/cmake.cxx b/Source/cmake.cxx index dbf961d..d4bbc14 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -335,7 +335,7 @@ cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind) // The "c" extension MUST precede the "C" extension. setupExts(this->CLikeSourceFileExtensions, { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "mpp", "m", "M", - "mm", "ixx", "cppm" }); + "mm", "ixx", "cppm", "ccm", "cxxm", "c++m" }); setupExts(this->HeaderFileExtensions, { "h", "hh", "h++", "hm", "hpp", "hxx", "in", "txx" }); setupExts(this->CudaFileExtensions, { "cu" }); diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 6cdd5a3..3bb7869 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -2528,6 +2528,12 @@ SystemTools::CopyStatus SystemTools::CloneFileContent( return status; #elif defined(__APPLE__) && \ defined(KWSYS_SYSTEMTOOLS_HAVE_MACOS_COPYFILE_CLONE) + // When running as root, copyfile() copies more metadata than we + // want, such as ownership. Pretend it is not available. + if (getuid() == 0) { + return CopyStatus{ Status::POSIX(ENOSYS), CopyStatus::NoPath }; + } + // NOTE: we cannot use `clonefile` as the {a,c,m}time for the file needs to // be updated by `copy_file_if_different` and `copy_file`. if (copyfile(source.c_str(), destination.c_str(), nullptr, diff --git a/Source/kwsys/kwsysPlatformTests.cmake b/Source/kwsys/kwsysPlatformTests.cmake index 89be4b8..6c006bc 100644 --- a/Source/kwsys/kwsysPlatformTests.cmake +++ b/Source/kwsys/kwsysPlatformTests.cmake @@ -8,9 +8,6 @@ macro(KWSYS_PLATFORM_TEST lang var description invert) if(NOT DEFINED ${var}_COMPILED) message(STATUS "${description}") set(maybe_cxx_standard "") - if(CMAKE_VERSION VERSION_LESS 3.8 AND CMAKE_CXX_STANDARD) - set(maybe_cxx_standard "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}") - endif() try_compile(${var}_COMPILED ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} @@ -18,14 +15,16 @@ macro(KWSYS_PLATFORM_TEST lang var description invert) CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=${KWSYS_PLATFORM_TEST_LINK_LIBRARIES}" ${maybe_cxx_standard} OUTPUT_VARIABLE OUTPUT) - if(${var}_COMPILED) - file(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "${description} compiled with the following output:\n${OUTPUT}\n\n") - else() - file(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} failed to compile with the following output:\n${OUTPUT}\n\n") + if(CMAKE_VERSION VERSION_LESS 3.26) + if(${var}_COMPILED) + file(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "${description} compiled with the following output:\n${OUTPUT}\n\n") + else() + file(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "${description} failed to compile with the following output:\n${OUTPUT}\n\n") + endif() endif() if(${invert} MATCHES INVERT) if(${var}_COMPILED) @@ -67,19 +66,23 @@ macro(KWSYS_PLATFORM_TEST_RUN lang var description invert) # Note that ${var} will be a 0 return value on success. if(${var}_COMPILED) - if(${var}) + if(CMAKE_VERSION VERSION_LESS 3.26) + if(${var}) + file(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "${description} compiled but failed to run with the following output:\n${OUTPUT}\n\n") + else() + file(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "${description} compiled and ran with the following output:\n${OUTPUT}\n\n") + endif() + endif() + else() + if(CMAKE_VERSION VERSION_LESS 3.26) file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} compiled but failed to run with the following output:\n${OUTPUT}\n\n") - else() - file(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "${description} compiled and ran with the following output:\n${OUTPUT}\n\n") + "${description} failed to compile with the following output:\n${OUTPUT}\n\n") endif() - else() - file(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} failed to compile with the following output:\n${OUTPUT}\n\n") set(${var} -1 CACHE INTERNAL "${description} failed to compile.") endif() @@ -188,14 +191,16 @@ macro(KWSYS_PLATFORM_INFO_TEST lang var description) OUTPUT_VARIABLE OUTPUT COPY_FILE ${KWSYS_PLATFORM_INFO_FILE} ) - if(${var}_COMPILED) - file(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "${description} compiled with the following output:\n${OUTPUT}\n\n") - else() - file(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} failed to compile with the following output:\n${OUTPUT}\n\n") + if(CMAKE_VERSION VERSION_LESS 3.26) + if(${var}_COMPILED) + file(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "${description} compiled with the following output:\n${OUTPUT}\n\n") + else() + file(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "${description} failed to compile with the following output:\n${OUTPUT}\n\n") + endif() endif() if(${var}_COMPILED) message(STATUS "${description} - compiled") |