Commit 9f5c2040 authored by Brad King's avatar Brad King

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
parent 0f150b69
......@@ -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()
......@@ -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()
......@@ -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;
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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;
......
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)
......@@ -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})
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment