瀏覽代碼

AIX: Explicitly compute executable exports for both XL and GNU

On AIX, symbols in executables must be exported in order to be visible
to modules (plugins) they load via `dlopen`.  Prior to policy `CMP0065`,
CMake linked all executables with flags to export symbols, but the NEW
behavior for that policy is to do so only for executables that have the
`ENABLE_EXPORTS` target property set.  In both cases, CMake has always
used the AIX linker option `-bexpall` option to export symbols from
executables.

This has worked fairly well with the XL compiler, but with the GNU
compiler it works only for C ABI symbols.  The reason is that `-bexpall`
does not export symbols starting in `_` but the GNU C++ ABI mangles all
symbols with a leading `_`.  Therefore we have only supported C ABI
plugins with the GNU compiler on AIX.  Some projects have tried to work
around this by replacing `-bexpall` with `-bexpfull`, but the latter
often exports symbols that we do not want exported.

Avoid using `-bexpall` for executables by instead using by our own
internal `ExportImportList` script to compute symbol export lists from
the object files to be linked into an executable.  Pass the explicitly
computed export list to the AIX linker's `-bE:...` option.  We already
do this for shared object exports.

Issue: #19163
Brad King 6 年之前
父節點
當前提交
9f5c2040bf

+ 5 - 1
Modules/Platform/AIX-GNU.cmake

@@ -18,7 +18,7 @@ macro(__aix_compiler_gnu lang)
   set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG "-Wl,-blibpath:")
   set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":")
   string(APPEND CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS " -Wl,-G,-bnoipath")
-  set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-Wl,-bexpall")
+  set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-Wl,-bexpall") # CMP0065 old behavior
   set(CMAKE_${lang}_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH 1)
 
   set(CMAKE_${lang}_LINK_FLAGS "-Wl,-bnoipath")
@@ -32,4 +32,8 @@ macro(__aix_compiler_gnu lang)
     "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/objects.exp <OBJECTS>"
     "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/objects.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
     )
+
+  set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
+    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/objects.exp <OBJECTS>"
+    "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<OBJECT_DIR>/objects.exp <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endmacro()

+ 5 - 1
Modules/Platform/AIX-XL.cmake

@@ -18,7 +18,7 @@ macro(__aix_compiler_xl lang)
   set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG "-Wl,-blibpath:")
   set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":")
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-G -Wl,-bnoipath")  # -shared
-  set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-Wl,-bexpall")
+  set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-Wl,-bexpall") # CMP0065 old behavior
   set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS " ")
   set(CMAKE_SHARED_MODULE_${lang}_FLAGS  " ")
 
@@ -30,4 +30,8 @@ macro(__aix_compiler_xl lang)
     "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/objects.exp <OBJECTS>"
     "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/objects.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
     )
+
+  set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
+    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/objects.exp <OBJECTS>"
+    "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<OBJECT_DIR>/objects.exp <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endmacro()

+ 7 - 0
Source/cmGeneratorTarget.cxx

@@ -2754,6 +2754,13 @@ std::string cmGeneratorTarget::GetCreateRuleVariable(
     case cmStateEnums::MODULE_LIBRARY:
       return "CMAKE_" + lang + "_CREATE_SHARED_MODULE";
     case cmStateEnums::EXECUTABLE:
+      if (this->IsExecutableWithExports()) {
+        std::string linkExeWithExports =
+          "CMAKE_" + lang + "_LINK_EXECUTABLE_WITH_EXPORTS";
+        if (this->Makefile->IsDefinitionSet(linkExeWithExports)) {
+          return linkExeWithExports;
+        }
+      }
       return "CMAKE_" + lang + "_LINK_EXECUTABLE";
     default:
       break;

+ 8 - 4
Source/cmLocalGenerator.cxx

@@ -1515,8 +1515,10 @@ std::string cmLocalGenerator::GetLinkLibsCMP0065(
         }
         CM_FALLTHROUGH;
       case cmPolicies::OLD:
-        // OLD behavior is to always add the flags
-        add_shlib_flags = true;
+        // 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"));
         break;
       case cmPolicies::REQUIRED_IF_USED:
       case cmPolicies::REQUIRED_ALWAYS:
@@ -1525,8 +1527,10 @@ std::string cmLocalGenerator::GetLinkLibsCMP0065(
           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0065));
         CM_FALLTHROUGH;
       case cmPolicies::NEW:
-        // NEW behavior is to only add the flags if ENABLE_EXPORTS is on
-        add_shlib_flags = tgt.GetPropertyAsBool("ENABLE_EXPORTS");
+        // 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");
         break;
     }
 

+ 11 - 0
Source/cmTarget.cxx

@@ -171,6 +171,7 @@ public:
   bool IsGeneratorProvided;
   bool HaveInstallRule;
   bool IsDLLPlatform;
+  bool IsAIX;
   bool IsAndroid;
   bool IsImportedTarget;
   bool ImportedGloballyVisible;
@@ -219,6 +220,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
   impl->IsGeneratorProvided = false;
   impl->HaveInstallRule = false;
   impl->IsDLLPlatform = false;
+  impl->IsAIX = false;
   impl->IsAndroid = false;
   impl->IsImportedTarget =
     (vis == VisibilityImported || vis == VisibilityImportedGlobally);
@@ -229,6 +231,10 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
   impl->IsDLLPlatform =
     !impl->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
 
+  // Check whether we are targeting AIX.
+  impl->IsAIX =
+    (impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "AIX");
+
   // Check whether we are targeting an Android platform.
   impl->IsAndroid =
     (impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android");
@@ -1664,6 +1670,11 @@ bool cmTarget::IsDLLPlatform() const
   return impl->IsDLLPlatform;
 }
 
+bool cmTarget::IsAIX() const
+{
+  return impl->IsAIX;
+}
+
 bool cmTarget::IsImported() const
 {
   return impl->IsImportedTarget;

+ 3 - 0
Source/cmTarget.h

@@ -180,6 +180,9 @@ public:
   //! Return whether or not the target is for a DLL platform.
   bool IsDLLPlatform() const;
 
+  //! Return whether or not we are targeting AIX.
+  bool IsAIX() const;
+
   bool IsImported() const;
   bool IsImportedGloballyVisible() const;
 

+ 5 - 2
Tests/RunCMake/CMP0065/RunCMakeTest.cmake

@@ -1,8 +1,11 @@
 include(RunCMake)
 
 run_cmake(OLDBad1)
-run_cmake(OLDBad2)
-run_cmake(NEWBad)
+if(NOT CMAKE_SYSTEM_NAME STREQUAL "AIX")
+  # Tests with ENABLE_EXPORTS ON.  For AIX we do not use the flags at all.
+  run_cmake(OLDBad2)
+  run_cmake(NEWBad)
+endif()
 run_cmake(NEWGood)
 run_cmake(WARN-OFF)
 run_cmake(WARN-ON)

+ 1 - 1
Tests/RunCMake/CMakeLists.txt

@@ -120,7 +120,7 @@ add_RunCMake_test(CMP0081)
 # CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode
 # generators ignore.  The policy will have no effect on those generators.
 if(NOT CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
-  add_RunCMake_test(CMP0065)
+  add_RunCMake_test(CMP0065 -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
 endif()
 if(CMAKE_GENERATOR MATCHES "Make")
   add_RunCMake_test(Make -DMAKE_IS_GNU=${MAKE_IS_GNU})