Browse Source

AIX: Add an option to disable automatic exports from shared libraries

Since commit 0f150b69d3 (AIX: Explicitly compute shared object exports
for both XL and GNU, 2019-07-11, v3.16.0-rc1~418^2~2) we always export
all symbols from shared libraries by default.  Add a new target property
called `AIX_EXPORT_ALL_SYMBOLS` that can be explicitly set to OFF to
suppress this behavior and export no symbols by default.

Fixes: #20290
Brad King 5 years ago
parent
commit
afcd9fe669

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

@@ -104,6 +104,7 @@ Properties on Targets
    :maxdepth: 1
 
    /prop_tgt/ADDITIONAL_CLEAN_FILES
+   /prop_tgt/AIX_EXPORT_ALL_SYMBOLS
    /prop_tgt/ALIASED_TARGET
    /prop_tgt/ANDROID_ANT_ADDITIONAL_OPTIONS
    /prop_tgt/ANDROID_API

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

@@ -323,6 +323,7 @@ Variables that Control the Build
 .. toctree::
    :maxdepth: 1
 
+   /variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS
    /variable/CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS
    /variable/CMAKE_ANDROID_API
    /variable/CMAKE_ANDROID_API_MIN

+ 12 - 0
Help/prop_tgt/AIX_EXPORT_ALL_SYMBOLS.rst

@@ -0,0 +1,12 @@
+AIX_EXPORT_ALL_SYMBOLS
+----------------------
+
+On AIX, CMake automatically exports all symbols from shared libraries, and
+from executables with the :prop_tgt:`ENABLE_EXPORTS` target property set.
+Explicitly disable this boolean property to suppress the behavior and
+export no symbols by default.  In this case it is expected that the project
+will use other means to export some symbols.
+
+This property is initialized by the value of
+the :variable:`CMAKE_AIX_EXPORT_ALL_SYMBOLS` variable if it is set
+when a target is created.

+ 7 - 0
Help/release/dev/aix-no-export-all.rst

@@ -0,0 +1,7 @@
+aix-no-export-all
+-----------------
+
+* The :prop_tgt:`AIX_EXPORT_ALL_SYMBOLS` target property and associated
+  :variable:`CMAKE_AIX_EXPORT_ALL_SYMBOLS` variable were created to
+  optionally explicitly disbale automatic export of symbols from shared
+  libraries on AIX.

+ 6 - 0
Help/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS.rst

@@ -0,0 +1,6 @@
+CMAKE_AIX_EXPORT_ALL_SYMBOLS
+----------------------------
+
+Default value for :prop_tgt:`AIX_EXPORT_ALL_SYMBOLS` target property.
+This variable is used to initialize the property on each target as it is
+created.

+ 2 - 2
Modules/Platform/AIX-GNU.cmake

@@ -23,11 +23,11 @@ macro(__aix_compiler_gnu lang)
   # Construct the export list ourselves to pass only the object files so
   # that we export only the symbols actually provided by the sources.
   set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
-    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <OBJECTS>"
+    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <AIX_EXPORTS> <OBJECTS>"
     "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.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 <TARGET_IMPLIB> -l . <OBJECTS>"
+    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <AIX_EXPORTS> <OBJECTS>"
     "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endmacro()

+ 2 - 2
Modules/Platform/AIX-XL.cmake

@@ -29,12 +29,12 @@ macro(__aix_compiler_xl lang)
   # Construct the export list ourselves to pass only the object files so
   # that we export only the symbols actually provided by the sources.
   set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
-    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp${_OBJECTS}"
+    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <AIX_EXPORTS>${_OBJECTS}"
     "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.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 <TARGET_IMPLIB> -l . <OBJECTS>"
+    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <AIX_EXPORTS> <OBJECTS>"
     "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 
   unset(_OBJECTS)

+ 15 - 0
Source/cmCommonTargetGenerator.cxx

@@ -17,6 +17,7 @@
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
+#include "cmTarget.h"
 
 cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
   : GeneratorTarget(gt)
@@ -216,6 +217,20 @@ std::string cmCommonTargetGenerator::GetManifests(const std::string& config)
   return cmJoin(manifests, " ");
 }
 
+std::string cmCommonTargetGenerator::GetAIXExports(std::string const&)
+{
+  std::string aixExports;
+  if (this->GeneratorTarget->Target->IsAIX()) {
+    if (const char* exportAll =
+          this->GeneratorTarget->GetProperty("AIX_EXPORT_ALL_SYMBOLS")) {
+      if (cmIsOff(exportAll)) {
+        aixExports = "-n";
+      }
+    }
+  }
+  return aixExports;
+}
+
 void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags,
                                                const std::string& lang,
                                                const char* name, bool so)

+ 1 - 0
Source/cmCommonTargetGenerator.h

@@ -55,6 +55,7 @@ protected:
   std::string GetDefines(const std::string& l, const std::string& config);
   std::string GetIncludes(std::string const& l, const std::string& config);
   std::string GetManifests(const std::string& config);
+  std::string GetAIXExports(std::string const& config);
 
   std::vector<std::string> GetLinkedTargetDirectories(
     const std::string& config) const;

+ 3 - 0
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -196,6 +196,8 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
     this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
                             buildObjs, depends, useWatcomQuote);
 
+    std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
+
     cmRulePlaceholderExpander::RuleVariables vars;
     std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
 
@@ -219,6 +221,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
                                                   cmOutputConverter::SHELL);
 
     vars.Language = linkLanguage.c_str();
+    vars.AIXExports = aixExports.c_str();
     vars.Objects = buildObjs.c_str();
     vars.ObjectDir = objectDir.c_str();
     vars.Target = target.c_str();

+ 3 - 0
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -727,6 +727,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
           cmOutputConverter::SHELL);
     }
 
+    std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
+
     // maybe create .def file from list of objects
     this->GenDefFile(real_link_commands);
 
@@ -756,6 +758,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
     vars.CMTargetType =
       cmState::GetTargetTypeName(this->GeneratorTarget->GetType());
     vars.Language = linkLanguage.c_str();
+    vars.AIXExports = aixExports.c_str();
     vars.Objects = buildObjs.c_str();
     std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
 

+ 2 - 0
Source/cmNinjaNormalTargetGenerator.cxx

@@ -286,6 +286,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
 
     std::string lang = this->TargetLinkLanguage(config);
     vars.Language = config.c_str();
+    vars.AIXExports = "$AIX_EXPORTS";
 
     if (this->TargetLinkLanguage(config) == "Swift") {
       vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME";
@@ -955,6 +956,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
   vars["LINK_FLAGS"] = globalGen->EncodeLiteral(vars["LINK_FLAGS"]);
 
   vars["MANIFESTS"] = this->GetManifests(config);
+  vars["AIX_EXPORTS"] = this->GetAIXExports(config);
 
   vars["LINK_PATH"] = frameworkPath + linkPath;
   std::string lwyuFlags;

+ 5 - 0
Source/cmRulePlaceholderExpander.cxx

@@ -85,6 +85,11 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
       return replaceValues.ObjectsQuoted;
     }
   }
+  if (replaceValues.AIXExports) {
+    if (variable == "AIX_EXPORTS") {
+      return replaceValues.AIXExports;
+    }
+  }
   if (replaceValues.Defines && variable == "DEFINES") {
     return replaceValues.Defines;
   }

+ 1 - 0
Source/cmRulePlaceholderExpander.h

@@ -36,6 +36,7 @@ public:
     const char* TargetVersionMajor;
     const char* TargetVersionMinor;
     const char* Language;
+    const char* AIXExports;
     const char* Objects;
     const char* Target;
     const char* LinkLibraries;

+ 1 - 0
Source/cmTarget.cxx

@@ -491,6 +491,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
   }
   if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
       impl->TargetType == cmStateEnums::EXECUTABLE) {
+    initProp("AIX_EXPORT_ALL_SYMBOLS");
     initProp("WINDOWS_EXPORT_ALL_SYMBOLS");
   }
 

+ 1 - 0
Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-result.txt

@@ -0,0 +1 @@
+[^0]

+ 1 - 0
Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-stdout.txt

@@ -0,0 +1 @@
+ERROR: Undefined symbol: .AIXNotExported

+ 7 - 0
Tests/RunCMake/AutoExportDll/AIXExportExplicit.cmake

@@ -0,0 +1,7 @@
+enable_language(C)
+
+set(CMAKE_AIX_EXPORT_ALL_SYMBOLS OFF)
+add_library(AIXExportExplicitLib SHARED AIXExportExplicitLib.c)
+add_executable(AIXExportExplicitMain AIXExportExplicitMain.c)
+target_link_options(AIXExportExplicitLib PRIVATE LINKER:-bE:${CMAKE_CURRENT_SOURCE_DIR}/AIXExportExplicitLib.exp)
+target_link_libraries(AIXExportExplicitMain PRIVATE AIXExportExplicitLib)

+ 8 - 0
Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.c

@@ -0,0 +1,8 @@
+int AIXNotExported(void)
+{
+  return 0;
+}
+int AIXExportedSymbol(void)
+{
+  return 0;
+}

+ 1 - 0
Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.exp

@@ -0,0 +1 @@
+AIXExportedSymbol

+ 7 - 0
Tests/RunCMake/AutoExportDll/AIXExportExplicitMain.c

@@ -0,0 +1,7 @@
+extern int AIXNotExported(void);
+extern int AIXExportedSymbol(void);
+
+int main(void)
+{
+  return AIXNotExported() + AIXExportedSymbol();
+}

+ 11 - 0
Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake

@@ -55,3 +55,14 @@ if(EXPORTS)
     message(SEND_ERROR "\"${EXPORTS_DEF}\" has been updated.")
   endif()
 endif()
+
+function(run_AIXExportExplicit)
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/AIXExpotExplicit-build")
+  run_cmake(AIXExportExplicit)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_OUTPUT_MERGE TRUE)
+  run_cmake_command(AIXExportExplicit-build ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+  run_AIXExportExplicit()
+endif()

+ 4 - 1
Tests/RunCMake/CMakeLists.txt

@@ -614,7 +614,10 @@ endif()
 add_RunCMake_test_group(CPack "${cpack_tests}")
 # add a test to make sure symbols are exported from a shared library
 # for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used
-add_RunCMake_test(AutoExportDll -DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID})
+add_RunCMake_test(AutoExportDll
+  -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+  -DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}
+  )
 
 add_RunCMake_test(AndroidMK)