瀏覽代碼

OBJECT libraries: Properly recognize if sources depend on configuration

Fixes: #21198
Deniz Bahadir 5 年之前
父節點
當前提交
2f76e7429b

+ 2 - 3
Source/cmGeneratorExpressionNode.cxx

@@ -1664,9 +1664,8 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
       if (context->EvaluateForBuildsystem) {
         // Use object file directory with buildsystem placeholder.
         obj_dir = gt->ObjectDirectory;
-        // Here we assume that the set of object files produced
-        // by an object library does not vary with configuration
-        // and do not set HadContextSensitiveCondition to true.
+        context->HadContextSensitiveCondition =
+          gt->HasContextDependentSources();
       } else {
         // Use object file directory with per-config location.
         obj_dir = gt->GetObjectDirectory(context->Config);

+ 13 - 5
Source/cmGeneratorTarget.cxx

@@ -276,8 +276,8 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
   , DebugLinkDirectoriesDone(false)
   , DebugPrecompileHeadersDone(false)
   , DebugSourcesDone(false)
-  , SourcesAreContextDependent(true)
   , UtilityItemsDone(false)
+  , SourcesAreContextDependent(Tribool::Indeterminate)
 {
   this->Makefile = this->Target->GetMakefile();
   this->LocalGenerator = lg;
@@ -692,7 +692,7 @@ void cmGeneratorTarget::ClearSourcesCache()
 {
   this->AllConfigSources.clear();
   this->KindedSourcesMap.clear();
-  this->SourcesAreContextDependent = true;
+  this->SourcesAreContextDependent = Tribool::Indeterminate;
   this->Objects.clear();
   this->VisitedConfigsForObjects.clear();
 }
@@ -1653,10 +1653,13 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths(
                                              uniqueSrcs, debugSources);
   }
 
+  // Determine if sources are context-dependent or not.
   if (!contextDependentDirectSources &&
       !(contextDependentInterfaceSources && numFilesBefore < files.size()) &&
       !(contextDependentObjects && numFilesBefore2 < files.size())) {
-    this->SourcesAreContextDependent = false;
+    this->SourcesAreContextDependent = Tribool::False;
+  } else {
+    this->SourcesAreContextDependent = Tribool::True;
   }
 
   return files;
@@ -1731,9 +1734,9 @@ cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
 cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources(
   std::string const& config) const
 {
-  // If we already processed one configuration and found no dependenc
+  // If we already processed one configuration and found no dependency
   // on configuration then always use the one result.
-  if (!this->SourcesAreContextDependent) {
+  if (this->SourcesAreContextDependent == Tribool::False) {
     return this->KindedSourcesMap.begin()->second;
   }
 
@@ -7518,6 +7521,11 @@ bool cmGeneratorTarget::GetImplibGNUtoMS(std::string const& config,
   return false;
 }
 
+bool cmGeneratorTarget::HasContextDependentSources() const
+{
+  return this->SourcesAreContextDependent == Tribool::True;
+}
+
 bool cmGeneratorTarget::IsExecutableWithExports() const
 {
   return (this->GetType() == cmStateEnums::EXECUTABLE &&

+ 11 - 1
Source/cmGeneratorTarget.h

@@ -713,6 +713,10 @@ public:
   bool GetImplibGNUtoMS(std::string const& config, std::string const& gnuName,
                         std::string& out, const char* newExt = nullptr) const;
 
+  /** Can only ever return true if GetSourceFilePaths() was called before.
+      Otherwise, this is indeterminate and false will be assumed/returned!  */
+  bool HasContextDependentSources() const;
+
   bool IsExecutableWithExports() const;
 
   /** Return whether or not the target has a DLL import library.  */
@@ -1069,8 +1073,14 @@ private:
   mutable bool DebugLinkDirectoriesDone;
   mutable bool DebugPrecompileHeadersDone;
   mutable bool DebugSourcesDone;
-  mutable bool SourcesAreContextDependent;
   mutable bool UtilityItemsDone;
+  enum class Tribool
+  {
+    False = 0x0,
+    True = 0x1,
+    Indeterminate = 0x2
+  };
+  mutable Tribool SourcesAreContextDependent;
 
   bool ComputePDBOutputDir(const std::string& kind, const std::string& config,
                            std::string& out) const;

+ 16 - 1
Tests/ConfigSources/CMakeLists.txt

@@ -8,7 +8,12 @@ project(ConfigSources CXX)
 # Source file(s) named with the configuration(s).
 file(GENERATE
   OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp"
-  CONTENT "void config_$<CONFIG>() {}\n"
+  CONTENT [[
+#if defined(_WIN32) && defined(OBJ_SHARED)
+__declspec(dllexport)
+#endif
+void config_$<CONFIG>() {}
+]]
   )
 
 # Per-config sources via INTERFACE_SOURCES.
@@ -76,3 +81,13 @@ else()
 endif()
 add_library(OneConfigOnly OBJECT "$<$<CONFIG:${one_config}>:${CMAKE_CURRENT_SOURCE_DIR}/iface_src.cpp>")
 set_property(TARGET OneConfigOnly PROPERTY LINKER_LANGUAGE CXX)
+
+
+# ---------------------------------------------------------------------------
+# Makes sure that each configuration uses the correct generated file.
+add_library(ObjLibFromGeneratedSources OBJECT)
+set_property(TARGET ObjLibFromGeneratedSources PROPERTY POSITION_INDEPENDENT_CODE 1)
+target_compile_definitions(ObjLibFromGeneratedSources PRIVATE OBJ_SHARED)
+target_sources(ObjLibFromGeneratedSources PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp)
+add_library(SharedLibFromObjLibFromGeneratedSources SHARED shared.cpp)
+target_link_libraries(SharedLibFromObjLibFromGeneratedSources PRIVATE ObjLibFromGeneratedSources)

+ 8 - 0
Tests/ConfigSources/shared.cpp

@@ -0,0 +1,8 @@
+#if defined(_WIN32)
+#  define EXPORT __declspec(dllexport)
+#else
+#  define EXPORT
+#endif
+EXPORT void shared()
+{
+}