Browse Source

static library: add property STATIC_LIBRARY_OPTIONS

issue: #18251
Marc Chevrier 7 years ago
parent
commit
974de0e199

+ 1 - 0
Help/manual/cmake-properties.7.rst

@@ -301,6 +301,7 @@ Properties on Targets
    /prop_tgt/SOVERSION
    /prop_tgt/STATIC_LIBRARY_FLAGS_CONFIG
    /prop_tgt/STATIC_LIBRARY_FLAGS
+   /prop_tgt/STATIC_LIBRARY_OPTIONS
    /prop_tgt/SUFFIX
    /prop_tgt/TYPE
    /prop_tgt/VERSION

+ 5 - 4
Help/prop_tgt/LINK_FLAGS.rst

@@ -3,11 +3,12 @@ LINK_FLAGS
 
 Additional flags to use when linking this target if it is a shared library,
 module library, or an executable. Static libraries need to use
-:prop_tgt:`STATIC_LIBRARY_FLAGS`.
+:prop_tgt:`STATIC_LIBRARY_OPTIONS` or :prop_tgt:`STATIC_LIBRARY_FLAGS`
+properties.
 
-The LINK_FLAGS property, managed as a string, can be used to add extra flags
-to the link step of a target.  :prop_tgt:`LINK_FLAGS_<CONFIG>` will add to the
-configuration ``<CONFIG>``, for example, ``DEBUG``, ``RELEASE``,
+The ``LINK_FLAGS`` property, managed as a string, can be used to add extra
+flags to the link step of a target.  :prop_tgt:`LINK_FLAGS_<CONFIG>` will add
+to the configuration ``<CONFIG>``, for example, ``DEBUG``, ``RELEASE``,
 ``MINSIZEREL``, ``RELWITHDEBINFO``, ...
 
 .. note::

+ 2 - 1
Help/prop_tgt/LINK_FLAGS_CONFIG.rst

@@ -1,7 +1,8 @@
 LINK_FLAGS_<CONFIG>
 -------------------
 
-Per-configuration linker flags for a shared library, module or executable target.
+Per-configuration linker flags for a shared library, module or executable
+target.
 
 This is the configuration-specific version of :prop_tgt:`LINK_FLAGS`.
 

+ 4 - 1
Help/prop_tgt/LINK_OPTIONS.rst

@@ -1,7 +1,10 @@
 LINK_OPTIONS
 ------------
 
-List of options to use when linking this target.
+List of options to use for the link step of shared library, module
+and executable targets. Targets that are static libraries need to use
+the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property.
+
 
 This property holds a :ref:`;-list <CMake Language Lists>` of options
 specified so far for its target.  Use the :command:`target_link_options`

+ 8 - 3
Help/prop_tgt/STATIC_LIBRARY_FLAGS.rst

@@ -2,11 +2,16 @@ STATIC_LIBRARY_FLAGS
 --------------------
 
 Archiver (or MSVC librarian) flags for a static library target.
-Targets that are shared libraries, modules, or executables can use
-the :prop_tgt:`LINK_OPTIONS` or :prop_tgt:`LINK_FLAGS` target property.
+Targets that are shared libraries, modules, or executables need to use
+the :prop_tgt:`LINK_OPTIONS` or :prop_tgt:`LINK_FLAGS` target properties.
 
-The STATIC_LIBRARY_FLAGS property, managed as a string, can be used to add
+The ``STATIC_LIBRARY_FLAGS`` property, managed as a string, can be used to add
 extra flags to the link step of a static library target.
 :prop_tgt:`STATIC_LIBRARY_FLAGS_<CONFIG>` will add to the configuration
 ``<CONFIG>``, for example, ``DEBUG``, ``RELEASE``, ``MINSIZEREL``,
 ``RELWITHDEBINFO``, ...
+
+.. note::
+
+  This property has been superseded by :prop_tgt:`STATIC_LIBRARY_OPTIONS`
+  property.

+ 7 - 1
Help/prop_tgt/STATIC_LIBRARY_FLAGS_CONFIG.rst

@@ -1,6 +1,12 @@
 STATIC_LIBRARY_FLAGS_<CONFIG>
 -----------------------------
 
-Per-configuration archiver (or MSVC librarian) flags for a static library target.
+Per-configuration archiver (or MSVC librarian) flags for a static library
+target.
 
 This is the configuration-specific version of :prop_tgt:`STATIC_LIBRARY_FLAGS`.
+
+.. note::
+
+  This property has been superseded by :prop_tgt:`STATIC_LIBRARY_OPTIONS`
+  property.

+ 20 - 0
Help/prop_tgt/STATIC_LIBRARY_OPTIONS.rst

@@ -0,0 +1,20 @@
+STATIC_LIBRARY_OPTIONS
+----------------------
+
+Archiver (or MSVC librarian) flags for a static library target.
+Targets that are shared libraries, modules, or executables need to use
+the :prop_tgt:`LINK_OPTIONS` target property.
+
+This property holds a :ref:`;-list <CMake Language Lists>` of options
+specified so far for its target.  Use :command:`set_target_properties` or
+:command:`set_property` commands to set its content.
+
+Contents of ``STATIC_LIBRARY_OPTIONS`` may use "generator expressions" with the
+syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions.  See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
+
+.. note::
+
+  This property must be used in preference to :prop_tgt:`STATIC_LIBRARY_FLAGS`
+  property.

+ 4 - 0
Help/release/dev/STATIC_LIBRARY_OPTIONS.rst

@@ -0,0 +1,4 @@
+STATIC_LIBRARY_OPTIONS
+----------------------
+
+* static library targets gained new :prop_tgt:`STATIC_LIBRARY_OPTIONS` property.

+ 41 - 0
Source/cmGeneratorTarget.cxx

@@ -3017,6 +3017,47 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
   }
 }
 
+namespace {
+void processStaticLibraryLinkOptions(
+  cmGeneratorTarget const* tgt,
+  const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
+  std::vector<std::string>& options,
+  std::unordered_set<std::string>& uniqueOptions,
+  cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
+  std::string const& language)
+{
+  processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker,
+                         config, false, "static library link options",
+                         language, OptionsParse::Shell);
+}
+}
+
+void cmGeneratorTarget::GetStaticLibraryLinkOptions(
+  std::vector<std::string>& result, const std::string& config,
+  const std::string& language) const
+{
+  std::vector<cmGeneratorTarget::TargetPropertyEntry*> entries;
+  std::unordered_set<std::string> uniqueOptions;
+
+  cmGeneratorExpressionDAGChecker dagChecker(
+    this->GetName(), "STATIC_LIBRARY_OPTIONS", nullptr, nullptr);
+
+  if (const char* linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
+    std::vector<std::string> options;
+    cmGeneratorExpression ge;
+    cmSystemTools::ExpandListArgument(linkOptions, options);
+    for (const auto& option : options) {
+      std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(option);
+      entries.push_back(
+        new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+    }
+  }
+  processStaticLibraryLinkOptions(this, entries, result, uniqueOptions,
+                                  &dagChecker, config, language);
+
+  cmDeleteAll(entries);
+}
+
 namespace {
 void processLinkDepends(
   cmGeneratorTarget const* tgt,

+ 3 - 0
Source/cmGeneratorTarget.h

@@ -424,6 +424,9 @@ public:
   void GetLinkOptions(std::vector<std::string>& result,
                       const std::string& config,
                       const std::string& language) const;
+  void GetStaticLibraryLinkOptions(std::vector<std::string>& result,
+                                   const std::string& config,
+                                   const std::string& language) const;
 
   void GetLinkDepends(std::vector<std::string>& result,
                       const std::string& config,

+ 1 - 1
Source/cmGlobalXCodeGenerator.cxx

@@ -1844,7 +1844,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
   if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY ||
       gtgt->GetType() == cmStateEnums::STATIC_LIBRARY) {
     this->CurrentLocalGenerator->GetStaticLibraryFlags(
-      extraLinkOptions, cmSystemTools::UpperCase(configName), gtgt);
+      extraLinkOptions, cmSystemTools::UpperCase(configName), llang, gtgt);
   } else {
     const char* targetLinkFlags = gtgt->GetProperty("LINK_FLAGS");
     if (targetLinkFlags) {

+ 7 - 1
Source/cmLocalGenerator.cxx

@@ -979,6 +979,7 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
 
 void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags,
                                              std::string const& config,
+                                             std::string const& linkLanguage,
                                              cmGeneratorTarget* target)
 {
   this->AppendFlags(
@@ -992,6 +993,11 @@ void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags,
     std::string name = "STATIC_LIBRARY_FLAGS_" + config;
     this->AppendFlags(flags, target->GetProperty(name));
   }
+
+  std::vector<std::string> options;
+  target->GetStaticLibraryLinkOptions(options, config, linkLanguage);
+  // STATIC_LIBRARY_OPTIONS are escaped.
+  this->AppendCompileOptions(flags, options);
 }
 
 void cmLocalGenerator::GetTargetFlags(
@@ -1009,7 +1015,7 @@ void cmLocalGenerator::GetTargetFlags(
 
   switch (target->GetType()) {
     case cmStateEnums::STATIC_LIBRARY:
-      this->GetStaticLibraryFlags(linkFlags, buildType, target);
+      this->GetStaticLibraryFlags(linkFlags, buildType, linkLanguage, target);
       break;
     case cmStateEnums::MODULE_LIBRARY:
       libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS";

+ 1 - 0
Source/cmLocalGenerator.h

@@ -323,6 +323,7 @@ public:
 
   /** Fill out the static linker flags for the given target.  */
   void GetStaticLibraryFlags(std::string& flags, std::string const& config,
+                             std::string const& linkLanguage,
                              cmGeneratorTarget* target);
 
   /** Fill out these strings for the given target.  Libraries to link,

+ 3 - 1
Source/cmLocalVisualStudio7Generator.cxx

@@ -1038,7 +1038,9 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
         }
       }
       std::string libflags;
-      this->GetStaticLibraryFlags(libflags, configTypeUpper, target);
+      this->GetStaticLibraryFlags(libflags, configTypeUpper,
+                                  target->GetLinkerLanguage(configName),
+                                  target);
       if (!libflags.empty()) {
         fout << "\t\t\t\tAdditionalOptions=\"" << libflags << "\"\n";
       }

+ 1 - 1
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -148,7 +148,7 @@ void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
 
   std::string extraFlags;
   this->LocalGenerator->GetStaticLibraryFlags(
-    extraFlags, cmSystemTools::UpperCase(this->ConfigName),
+    extraFlags, cmSystemTools::UpperCase(this->ConfigName), linkLanguage,
     this->GeneratorTarget);
   this->WriteLibraryRules(linkRuleVar, extraFlags, false);
 }

+ 6 - 1
Source/cmVisualStudio10TargetGenerator.cxx

@@ -3055,9 +3055,14 @@ void cmVisualStudio10TargetGenerator::WriteLibOptions(
       this->GeneratorTarget->GetType() != cmStateEnums::OBJECT_LIBRARY) {
     return;
   }
+
+  const std::string& linkLanguage =
+    this->GeneratorTarget->GetLinkClosure(config)->LinkerLanguage;
+
   std::string libflags;
   this->LocalGenerator->GetStaticLibraryFlags(
-    libflags, cmSystemTools::UpperCase(config), this->GeneratorTarget);
+    libflags, cmSystemTools::UpperCase(config), linkLanguage,
+    this->GeneratorTarget);
   if (!libflags.empty()) {
     Elem e2(e1, "Lib");
     cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;

+ 7 - 0
Tests/RunCMake/LinkStatic/LinkOptionsLib.c

@@ -0,0 +1,7 @@
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+  int flags_lib(void)
+{
+  return 0;
+}

+ 27 - 0
Tests/RunCMake/LinkStatic/RunCMakeTest.cmake

@@ -1,3 +1,30 @@
 include(RunCMake)
 
 run_cmake(LINK_SEARCH_STATIC)
+
+
+macro(run_cmake_target test subtest target)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(${test}-${subtest} ${CMAKE_COMMAND} --build . --target ${target} ${ARGN})
+
+  unset(RunCMake_TEST_BINARY_DIR)
+  unset(RunCMake_TEST_NO_CLEAN)
+endmacro()
+
+if (NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
+  # Intel compiler does not reject bad flags or objects!
+  set(RunCMake_TEST_OUTPUT_MERGE TRUE)
+  if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
+  endif()
+
+  run_cmake(STATIC_LIBRARY_OPTIONS)
+
+  run_cmake_target(STATIC_LIBRARY_OPTIONS basic StaticLinkOptions)
+  run_cmake_target(STATIC_LIBRARY_OPTIONS genex StaticLinkOptions_genex --config Release)
+  run_cmake_target(STATIC_LIBRARY_OPTIONS shared SharedLinkOptions)
+
+  unset(RunCMake_TEST_OPTIONS)
+  unset(RunCMake_TEST_OUTPUT_MERGE)
+endif()

+ 4 - 0
Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-basic-check.cmake

@@ -0,0 +1,4 @@
+
+if (NOT actual_stdout MATCHES "BADFLAG")
+  set (RunCMake_TEST_FAILED "Not found expected 'BADFLAG'.")
+endif()

+ 1 - 0
Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-basic-result.txt

@@ -0,0 +1 @@
+.*

+ 7 - 0
Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-genex-check.cmake

@@ -0,0 +1,7 @@
+
+if (NOT actual_stdout MATCHES "BADFLAG_RELEASE")
+  set (RunCMake_TEST_FAILED "Not found expected 'BADFLAG_RELEASE'.")
+endif()
+if (actual_stdout MATCHES "SHELL:")
+  string (APPEND RunCMake_TEST_FAILED "\nFound unexpected prefix 'SHELL:'.")
+endif()

+ 1 - 0
Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-genex-result.txt

@@ -0,0 +1 @@
+.*

+ 4 - 0
Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-shared-check.cmake

@@ -0,0 +1,4 @@
+
+if (actual_stdout MATCHES "BADFLAG")
+  string (APPEND RunCMake_TEST_FAILED "\nFound unexpected flag 'BADFLAG'.")
+endif()

+ 1 - 0
Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-shared-result.txt

@@ -0,0 +1 @@
+.*

+ 21 - 0
Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS.cmake

@@ -0,0 +1,21 @@
+
+enable_language(C)
+
+set(obj "${CMAKE_C_OUTPUT_EXTENSION}")
+if(BORLAND)
+  set(pre -)
+endif()
+
+add_library(StaticLinkOptions STATIC LinkOptionsLib.c)
+set_property(TARGET StaticLinkOptions PROPERTY STATIC_LIBRARY_OPTIONS ${pre}BADFLAG${obj})
+
+# static library with generator expression
+add_library(StaticLinkOptions_genex STATIC LinkOptionsLib.c)
+set_property(TARGET StaticLinkOptions_genex PROPERTY STATIC_LIBRARY_OPTIONS
+  $<$<CONFIG:Release>:${pre}BADFLAG_RELEASE${obj}>
+  "SHELL:" # produces no options
+  )
+
+# shared library do not use property STATIC_LIBRARY_OPTIONS
+add_library(SharedLinkOptions SHARED LinkOptionsLib.c)
+set_property(TARGET SharedLinkOptions PROPERTY STATIC_LIBRARY_OPTIONS ${pre}BADFLAG${obj})