Merge topic 'aix-archive-shared-libraries'

d27fe9dfba AIX: Add option to archive shared libraries
98013ad1ca cmXCOFF: Add support for editing binary inside an archive

Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Merge-request: !9606
This commit is contained in:
Brad King
2024-07-19 13:55:32 +00:00
committed by Kitware Robot
28 changed files with 343 additions and 20 deletions

View File

@@ -109,6 +109,7 @@ Properties on Targets
/prop_tgt/ADDITIONAL_CLEAN_FILES
/prop_tgt/AIX_EXPORT_ALL_SYMBOLS
/prop_tgt/AIX_SHARED_LIBRARY_ARCHIVE
/prop_tgt/ALIAS_GLOBAL
/prop_tgt/ALIASED_TARGET
/prop_tgt/ANDROID_ANT_ADDITIONAL_OPTIONS

View File

@@ -106,6 +106,7 @@ Variables that Provide Information
/variable/CMAKE_SCRIPT_MODE_FILE
/variable/CMAKE_SHARED_LIBRARY_PREFIX
/variable/CMAKE_SHARED_LIBRARY_SUFFIX
/variable/CMAKE_SHARED_LIBRARY_ARCHIVE_SUFFIX
/variable/CMAKE_SHARED_MODULE_PREFIX
/variable/CMAKE_SHARED_MODULE_SUFFIX
/variable/CMAKE_SIZEOF_VOID_P
@@ -361,6 +362,7 @@ Variables that Control the Build
:maxdepth: 1
/variable/CMAKE_ADSP_ROOT
/variable/CMAKE_AIX_SHARED_LIBRARY_ARCHIVE
/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS
/variable/CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS
/variable/CMAKE_ANDROID_API
@@ -615,6 +617,7 @@ Variables for Languages
/variable/CMAKE_LANG_COMPILER_TARGET
/variable/CMAKE_LANG_COMPILER_VERSION
/variable/CMAKE_LANG_CREATE_SHARED_LIBRARY
/variable/CMAKE_LANG_CREATE_SHARED_LIBRARY_ARCHIVE
/variable/CMAKE_LANG_CREATE_SHARED_MODULE
/variable/CMAKE_LANG_CREATE_STATIC_LIBRARY
/variable/CMAKE_LANG_EXTENSIONS

View File

@@ -0,0 +1,20 @@
AIX_SHARED_LIBRARY_ARCHIVE
--------------------------
.. versionadded:: 3.31
On AIX, enable creation of a shared library archive. This places
the shared object ``.so`` file inside an archive ``.a`` file.
By default, CMake creates shared libraries on AIX as plain
shared object ``.so`` files for consistency with other UNIX platforms.
Alternatively, set this property to a true value to create a shared
library archive instead, as is AIX convention.
When a shared library is archived the shared object in the archive
does not record any version information from :prop_tgt:`VERSION` or
:prop_tgt`SOVERSION` target properties.
This property defaults to :variable:`CMAKE_AIX_SHARED_LIBRARY_ARCHIVE`
if that variable is set when a ``SHARED`` library target is created
by :command:`add_library`.

View File

@@ -0,0 +1,6 @@
aix-archive-shared-libraries
----------------------------
* On AIX, shared libraries may now be created as shared library archives.
See the :variable:`CMAKE_AIX_SHARED_LIBRARY_ARCHIVE` variable
and :prop_tgt:`AIX_SHARED_LIBRARY_ARCHIVE` target property.

View File

@@ -0,0 +1,10 @@
CMAKE_AIX_SHARED_LIBRARY_ARCHIVE
--------------------------------
.. versionadded:: 3.31
On AIX, enable creation of shared library archives.
This variable initializes the :prop_tgt:`AIX_SHARED_LIBRARY_ARCHIVE`
target property on ``SHARED`` library targets as they are created
by :command:`add_library`. See that target property for details.

View File

@@ -0,0 +1,8 @@
CMAKE_<LANG>_CREATE_SHARED_LIBRARY_ARCHIVE
------------------------------------------
Rule variable to create a shared library with archive.
This is a rule variable that tells CMake how to create a shared
library with an archive for the language <LANG>. This rule variable
is a ; delimited list of commands to run to perform the linking step.

View File

@@ -0,0 +1,7 @@
CMAKE_SHARED_LIBRARY_ARCHIVE_SUFFIX
-----------------------------------
The suffix for archived shared libraries that you link to.
The suffix to use for the end of a archive containing a
shared library, ``.a`` on AIX.

View File

@@ -30,6 +30,14 @@ macro(__aix_compiler_gnu lang)
"<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>"
)
# Create an archive for shared library if CMAKE_AIX_SHARED_LIBRARY_ARCHIVE is used.
string(REPLACE " <SONAME_FLAG><TARGET_SONAME> -o <TARGET>" " -o <TARGET_SONAME>"
CMAKE_${lang}_CREATE_SHARED_LIBRARY_ARCHIVE "${CMAKE_${lang}_CREATE_SHARED_LIBRARY}")
list(APPEND CMAKE_${lang}_CREATE_SHARED_LIBRARY_ARCHIVE
"<CMAKE_AR> -X32_64 rc <TARGET> <TARGET_SONAME>"
"rm -f <TARGET_SONAME>"
)
set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
"\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -c <CMAKE_${lang}_COMPILER> -l . <AIX_EXPORTS> <OBJECTS>"
"<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")

View File

@@ -34,6 +34,14 @@ macro(__aix_compiler_xl lang)
"<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>"
)
# Create an archive for shared library if CMAKE_AIX_SHARED_LIBRARY_ARCHIVE is used.
string(REPLACE " <SONAME_FLAG><TARGET_SONAME> -o <TARGET>" " -o <TARGET_SONAME>"
CMAKE_${lang}_CREATE_SHARED_LIBRARY_ARCHIVE "${CMAKE_${lang}_CREATE_SHARED_LIBRARY}")
list(APPEND CMAKE_${lang}_CREATE_SHARED_LIBRARY_ARCHIVE
"<CMAKE_AR> -X32_64 rc <TARGET> <TARGET_SONAME>"
"rm -f <TARGET_SONAME>"
)
set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
"\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -c <CMAKE_${lang}_COMPILER> -l . <AIX_EXPORTS> <OBJECTS>"
"<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")

View File

@@ -1,5 +1,6 @@
set(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
set(CMAKE_SHARED_LIBRARY_SUFFIX ".so") # .so
set(CMAKE_SHARED_LIBRARY_ARCHIVE_SUFFIX ".a") # .a
set(CMAKE_AIX_IMPORT_FILE_PREFIX "")
set(CMAKE_AIX_IMPORT_FILE_SUFFIX ".imp")
set(CMAKE_DL_LIBS "-lld")

View File

@@ -6,6 +6,7 @@ CMAKE_STATIC_LIBRARY_PREFIX == "${CMAKE_STATIC_LIBRARY_PREFIX}"
CMAKE_STATIC_LIBRARY_SUFFIX == "${CMAKE_STATIC_LIBRARY_SUFFIX}"
CMAKE_SHARED_LIBRARY_PREFIX == "${CMAKE_SHARED_LIBRARY_PREFIX}"
CMAKE_SHARED_LIBRARY_SUFFIX == "${CMAKE_SHARED_LIBRARY_SUFFIX}"
CMAKE_SHARED_LIBRARY_ARCHIVE_SUFFIX == "${CMAKE_SHARED_LIBRARY_ARCHIVE_SUFFIX}"
CMAKE_SHARED_MODULE_PREFIX == "${CMAKE_SHARED_MODULE_PREFIX}"
CMAKE_SHARED_MODULE_SUFFIX == "${CMAKE_SHARED_MODULE_SUFFIX}"

View File

@@ -2294,6 +2294,9 @@ std::string cmGeneratorTarget::GetCreateRuleVariable(
return this->GetFeatureSpecificLinkRuleVariable(var, lang, config);
}
case cmStateEnums::SHARED_LIBRARY:
if (this->IsArchivedAIXSharedLibrary()) {
return "CMAKE_" + lang + "_CREATE_SHARED_LIBRARY_ARCHIVE";
}
return "CMAKE_" + lang + "_CREATE_SHARED_LIBRARY";
case cmStateEnums::MODULE_LIBRARY:
return "CMAKE_" + lang + "_CREATE_SHARED_MODULE";
@@ -2938,7 +2941,7 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
cmValue soversion = this->GetProperty("SOVERSION");
if (!this->HasSOName(config) ||
this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") ||
this->IsFrameworkOnApple()) {
this->IsFrameworkOnApple() || this->IsArchivedAIXSharedLibrary()) {
// Versioning is supported only for shared libraries and modules,
// and then only when the platform supports an soname flag.
version = nullptr;
@@ -2971,6 +2974,11 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
}
targetNames.Real += cmStrCat(targetNames.Base, components.suffix);
targetNames.SharedObject = targetNames.Real;
} else if (this->IsArchivedAIXSharedLibrary()) {
targetNames.SharedObject =
cmStrCat(components.prefix, targetNames.Base, ".so");
targetNames.Real =
cmStrCat(components.prefix, targetNames.Base, components.suffix);
} else {
// The library's soname.
this->ComputeVersionedName(targetNames.SharedObject, components.prefix,
@@ -3054,8 +3062,13 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
// The executable name.
targetNames.Base = components.base;
targetNames.Output =
components.prefix + targetNames.Base + components.suffix;
if (this->IsArchivedAIXSharedLibrary()) {
targetNames.Output = components.prefix + targetNames.Base;
} else {
targetNames.Output =
components.prefix + targetNames.Base + components.suffix;
}
// The executable's real name on disk.
#if defined(__CYGWIN__)
@@ -4801,6 +4814,11 @@ bool cmGeneratorTarget::IsFrameworkOnApple() const
return this->Target->IsFrameworkOnApple();
}
bool cmGeneratorTarget::IsArchivedAIXSharedLibrary() const
{
return this->Target->IsArchivedAIXSharedLibrary();
}
bool cmGeneratorTarget::IsImportedFrameworkFolderOnApple(
const std::string& config) const
{

View File

@@ -891,6 +891,9 @@ public:
/** Return whether this target is a CFBundle (plugin) on Apple. */
bool IsCFBundleOnApple() const;
/** Return whether this target is a shared library on AIX. */
bool IsArchivedAIXSharedLibrary() const;
/** Assembly types. The order of the values of this enum is relevant
because of smaller/larger comparison operations! */
enum ManagedType

View File

@@ -66,7 +66,7 @@ void computeFilesToInstall(
// Library interface name.
std::string fromSOName;
std::string toSOName;
if (library != output) {
if (!library.empty() && library != output) {
haveNamelink = true;
fromSOName = cmStrCat(fromDirConfig, library);
toSOName = library;
@@ -403,6 +403,10 @@ cmInstallTargetGenerator::Files cmInstallTargetGenerator::GetFiles(
files.From.emplace_back(std::move(from1));
files.To.emplace_back(std::move(to1));
} else if (this->Target->IsArchivedAIXSharedLibrary()) {
// Install only the archive on AIX.
computeFilesToInstall(files, this->NamelinkMode, fromDirConfig,
targetNames.Output, {}, targetNames.Real);
} else {
computeFilesToInstall(files, this->NamelinkMode, fromDirConfig,
targetNames.Output, targetNames.SharedObject,

View File

@@ -169,6 +169,11 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
std::string linkRuleVar =
cmStrCat("CMAKE_", linkLanguage, "_CREATE_SHARED_LIBRARY");
if (this->GeneratorTarget->IsArchivedAIXSharedLibrary()) {
linkRuleVar =
cmStrCat("CMAKE_", linkLanguage, "_CREATE_SHARED_LIBRARY_ARCHIVE");
}
std::string extraFlags;
this->GetTargetLinkFlags(extraFlags, linkLanguage);
this->LocalGenerator->AddConfigVariableFlags(
@@ -788,7 +793,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
vars.LinkLibraries = linkLibs.c_str();
vars.ObjectsQuoted = buildObjs.c_str();
std::string targetOutSOName;
if (this->GeneratorTarget->HasSOName(this->GetConfigName())) {
if (this->GeneratorTarget->HasSOName(this->GetConfigName()) ||
this->GeneratorTarget->IsArchivedAIXSharedLibrary()) {
vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage);
targetOutSOName = this->LocalGenerator->ConvertToOutputFormat(
this->TargetNames.SharedObject, cmOutputConverter::SHELL);

View File

@@ -1459,7 +1459,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
cmNinjaVars symlinkVars;
bool const symlinkNeeded =
(targetOutput != targetOutputReal && !gt->IsFrameworkOnApple());
(targetOutput != targetOutputReal && !gt->IsFrameworkOnApple() &&
!gt->IsArchivedAIXSharedLibrary());
if (!symlinkNeeded) {
vars["POST_BUILD"] = postBuildCmdLine;
} else {

View File

@@ -407,6 +407,8 @@ TargetProperty const StaticTargetProperties[] = {
{ "VS_USE_DEBUG_LIBRARIES"_s, IC::NonImportedTarget },
// ---- OpenWatcom
{ "WATCOM_RUNTIME_LIBRARY"_s, IC::CanCompileSources },
// ---- AIX
{ "AIX_SHARED_LIBRARY_ARCHIVE"_s, IC::SharedLibraryTarget },
// -- Language
// ---- C
COMMON_LANGUAGE_PROPERTIES(C),
@@ -1284,6 +1286,12 @@ bool cmTarget::IsFrameworkOnApple() const
this->IsApple() && this->GetPropertyAsBool("FRAMEWORK"));
}
bool cmTarget::IsArchivedAIXSharedLibrary() const
{
return (this->GetType() == cmStateEnums::SHARED_LIBRARY && this->IsAIX() &&
this->GetPropertyAsBool("AIX_SHARED_LIBRARY_ARCHIVE"));
}
bool cmTarget::IsAppBundleOnApple() const
{
return (this->GetType() == cmStateEnums::EXECUTABLE && this->IsApple() &&
@@ -2997,7 +3005,9 @@ const char* cmTarget::GetSuffixVariableInternal(
case cmStateEnums::SHARED_LIBRARY:
switch (artifact) {
case cmStateEnums::RuntimeBinaryArtifact:
return "CMAKE_SHARED_LIBRARY_SUFFIX";
return this->IsArchivedAIXSharedLibrary()
? "CMAKE_SHARED_LIBRARY_ARCHIVE_SUFFIX"
: "CMAKE_SHARED_LIBRARY_SUFFIX";
case cmStateEnums::ImportLibraryArtifact:
return this->IsApple() ? "CMAKE_APPLE_IMPORT_FILE_SUFFIX"
: "CMAKE_IMPORT_LIBRARY_SUFFIX";

View File

@@ -234,6 +234,9 @@ public:
//! Return whether this target is a shared library Framework on Apple.
bool IsFrameworkOnApple() const;
//! Return whether to archive shared library or not on AIX.
bool IsArchivedAIXSharedLibrary() const;
//! Return whether this target is an executable Bundle on Apple.
bool IsAppBundleOnApple() const;

View File

@@ -16,10 +16,19 @@
# define __XCOFF32__
# define __XCOFF64__
# include <xcoff.h>
# define __AR_BIG__
# include <ar.h>
#else
# error "This source may be compiled only on AIX."
#endif
// Function to align a number num with align_num bytes.
size_t align(size_t num, int align_num)
{
align_num = 1 << (align_num);
return (((num + align_num - 1) / align_num) * align_num);
}
class cmXCOFFInternal
{
public:
@@ -79,6 +88,12 @@ struct XCOFF64
};
const unsigned char xcoff64_magic[] = { 0x01, 0xF7 };
enum class IsArchive
{
No,
Yes,
};
template <typename XCOFF>
class Impl : public cmXCOFFInternal
{
@@ -93,6 +108,20 @@ class Impl : public cmXCOFFInternal
std::streamoff LoaderImportFileTablePos = 0;
std::vector<char> LoaderImportFileTable;
bool Read(fl_hdr& x)
{
// FIXME: Add byte swapping if needed.
return static_cast<bool>(
this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)));
}
bool Read(ar_hdr& x)
{
// FIXME: Add byte swapping if needed.
return static_cast<bool>(
this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)));
}
bool Read(typename XCOFF::filehdr& x)
{
// FIXME: Add byte swapping if needed.
@@ -130,18 +159,40 @@ class Impl : public cmXCOFFInternal
public:
Impl(cmXCOFF* external, std::unique_ptr<std::iostream> fin,
cmXCOFF::Mode mode);
cmXCOFF::Mode mode, IsArchive IsBigArchive, int nextEvenBytePos);
cm::optional<cm::string_view> GetLibPath() override;
bool SetLibPath(cm::string_view libPath) override;
bool RemoveLibPath() override;
// Needed for SetLibPath () to move in a archive while write.
IsArchive is_big_archive;
int nextEvenByte;
int bytes_to_align;
};
template <typename XCOFF>
Impl<XCOFF>::Impl(cmXCOFF* external, std::unique_ptr<std::iostream> fin,
cmXCOFF::Mode mode)
cmXCOFF::Mode mode, IsArchive IsBigArchive,
int nextEvenBytePos)
: cmXCOFFInternal(external, std::move(fin), mode)
{
this->is_big_archive = IsBigArchive;
this->nextEvenByte = nextEvenBytePos;
if (this->is_big_archive == IsArchive::Yes) {
fl_hdr header;
this->Stream->read(reinterpret_cast<char*>(&header), sizeof(fl_hdr));
long long fstmoff = std::atoll(header.fl_fstmoff);
this->Stream->seekg(fstmoff, std::ios::beg);
ar_hdr arHeader;
this->Stream->read(reinterpret_cast<char*>(&arHeader), sizeof(ar_hdr));
// Move the pointer to next even byte after reading headers.
this->Stream->seekg(this->nextEvenByte, std::ios::cur);
}
if (!this->Read(this->FileHeader)) {
this->SetErrorMessage("Failed to read XCOFF file header.");
return;
@@ -158,6 +209,7 @@ Impl<XCOFF>::Impl(cmXCOFF* external, std::unique_ptr<std::iostream> fin,
this->SetErrorMessage("XCOFF loader section missing.");
return;
}
this->bytes_to_align = this->AuxHeader.o_algndata;
if (!this->Stream->seekg((this->AuxHeader.o_snloader - 1) *
sizeof(typename XCOFF::scnhdr),
std::ios::cur)) {
@@ -172,17 +224,33 @@ Impl<XCOFF>::Impl(cmXCOFF* external, std::unique_ptr<std::iostream> fin,
this->SetErrorMessage("XCOFF loader section header missing STYP_LOADER.");
return;
}
if (!this->Stream->seekg(this->LoaderSectionHeader.s_scnptr,
std::ios::beg)) {
if (is_big_archive == IsArchive::Yes) {
size_t header_len = this->nextEvenByte + sizeof(fl_hdr) + sizeof(ar_hdr);
size_t scnptrFromArchiveStart = this->LoaderSectionHeader.s_scnptr +
align(header_len, this->bytes_to_align);
if (!this->Stream->seekg(scnptrFromArchiveStart, std::ios::beg)) {
this->SetErrorMessage("Failed to seek to XCOFF loader header.");
return;
}
} else if (!this->Stream->seekg(this->LoaderSectionHeader.s_scnptr,
std::ios::beg)) {
this->SetErrorMessage("Failed to seek to XCOFF loader header.");
return;
}
if (!this->Read(this->LoaderHeader)) {
this->SetErrorMessage("Failed to read XCOFF loader header.");
return;
}
this->LoaderImportFileTablePos =
this->LoaderSectionHeader.s_scnptr + this->LoaderHeader.l_impoff;
if (is_big_archive == IsArchive::Yes) {
size_t header_len = sizeof(fl_hdr) + sizeof(ar_hdr) + this->nextEvenByte;
size_t scnptrFromArchiveStartPlusOff = this->LoaderSectionHeader.s_scnptr +
this->LoaderHeader.l_impoff + align(header_len, this->bytes_to_align);
this->LoaderImportFileTablePos = scnptrFromArchiveStartPlusOff;
} else {
this->LoaderImportFileTablePos =
this->LoaderSectionHeader.s_scnptr + this->LoaderHeader.l_impoff;
}
if (!this->Stream->seekg(this->LoaderImportFileTablePos)) {
this->SetErrorMessage(
"Failed to seek to XCOFF loader import file id table.");
@@ -251,9 +319,18 @@ bool Impl<XCOFF>::SetLibPath(cm::string_view libPath)
this->LoaderImportFileTable = std::move(ift);
}
if (!this->Stream->seekp(this->LoaderSectionHeader.s_scnptr +
offsetof(typename XCOFF::ldhdr, l_istlen),
std::ios::beg)) {
size_t scnptr;
if (this->is_big_archive == IsArchive::Yes) {
size_t header_len = sizeof(fl_hdr) + sizeof(ar_hdr) + this->nextEvenByte;
scnptr = this->LoaderSectionHeader.s_scnptr +
offsetof(typename XCOFF::ldhdr, l_istlen) +
align(header_len, this->bytes_to_align);
} else {
scnptr = this->LoaderSectionHeader.s_scnptr +
offsetof(typename XCOFF::ldhdr, l_istlen);
}
if (!this->Stream->seekp(scnptr, std::ios::beg)) {
this->SetErrorMessage(
"Failed to seek to XCOFF loader header import file id table length.");
return false;
@@ -285,6 +362,30 @@ bool Impl<XCOFF>::RemoveLibPath()
}
}
IsArchive check_if_big_archive(const char* fname)
{
int len = std::strlen(fname);
if (len < 2) {
return IsArchive::No;
}
if (std::strcmp(fname + len - 2, ".a") == 0) {
return IsArchive::Yes;
} else {
return IsArchive::No;
}
}
size_t getLastWordLen(const std::string& path)
{
std::size_t lastSlashPos = path.find_last_of("/\\");
if (lastSlashPos == std::string::npos) {
return path.length();
}
return (path.length() - lastSlashPos - 1);
}
//============================================================================
// External class implementation.
@@ -305,6 +406,44 @@ cmXCOFF::cmXCOFF(const char* fname, Mode mode)
// Read the XCOFF magic number.
unsigned char magic[2];
// To hold the length of the shared object name in the path.
int nextEvenByte = 0;
// Read archive name length.
int archive_name_length = 0;
// If a big archive, we will read the archive file headers first.
// Then move to the next even byte to get the magic number.
if (check_if_big_archive(fname) == IsArchive::Yes) {
fl_hdr header;
f->read(reinterpret_cast<char*>(&header), sizeof(fl_hdr));
if (std::strncmp(header.fl_magic, AIAMAGBIG, SAIAMAG) != 0) {
this->ErrorMessage = "Not a valid archive file or wrong format";
return;
}
long long fstmoff = std::atoll(header.fl_fstmoff);
f->seekg(fstmoff, std::ios::beg);
ar_hdr arHeader;
f->read(reinterpret_cast<char*>(&arHeader), sizeof(ar_hdr));
// We will sometimes get /opt/freeware/lib/libshared.a. So extract
// the last part only.
// Example: libshared.a [We need to length of "libshared.a" characters].
archive_name_length = static_cast<int>(getLastWordLen(std::string(fname)));
// Move to the next even byte.
if (archive_name_length % 2 == 0) {
nextEvenByte = archive_name_length + 2;
} else {
nextEvenByte = archive_name_length + 1;
}
f->seekg(nextEvenByte, std::ios::cur);
}
if (!f->read(reinterpret_cast<char*>(magic), sizeof(magic))) {
this->ErrorMessage = "Error reading XCOFF magic number.";
return;
@@ -316,9 +455,11 @@ cmXCOFF::cmXCOFF(const char* fname, Mode mode)
// Check the XCOFF type.
if (magic[0] == xcoff32_magic[0] && magic[1] == xcoff32_magic[1]) {
this->Internal = cm::make_unique<Impl<XCOFF32>>(this, std::move(f), mode);
this->Internal = cm::make_unique<Impl<XCOFF32>>(
this, std::move(f), mode, check_if_big_archive(fname), nextEvenByte);
} else if (magic[0] == xcoff64_magic[0] && magic[1] == xcoff64_magic[1]) {
this->Internal = cm::make_unique<Impl<XCOFF64>>(this, std::move(f), mode);
this->Internal = cm::make_unique<Impl<XCOFF64>>(
this, std::move(f), mode, check_if_big_archive(fname), nextEvenByte);
} else {
this->ErrorMessage = "File is not a XCOFF32 or XCOFF64 binary.";
}

View File

@@ -493,6 +493,7 @@ if(BUILD_TESTING)
ADD_TEST_MACRO(OutDir runtime/OutDir)
ADD_TEST_MACRO(OutName exe.OutName.exe)
ADD_TEST_MACRO(ObjectLibrary UseCshared)
ADD_TEST_MACRO(SharedLibraryArchive UseSLA)
ADD_TEST_MACRO(NewlineArgs NewlineArgs)
ADD_TEST_MACRO(SetLang SetLangX)
ADD_TEST_MACRO(EmptyProperty EmptyProperty)

View File

@@ -482,6 +482,9 @@ add_library(testMod1 MODULE empty.cpp)
add_library(testMod2 MODULE empty.cpp)
set_property(TARGET testMod2 PROPERTY BUNDLE 1)
add_library(testSharedLibArchiveAIX SHARED testSharedLibArchiveAIX.c)
set_property(TARGET testSharedLibArchiveAIX PROPERTY AIX_SHARED_LIBRARY_ARCHIVE 1)
install(TARGETS testLibRequired
EXPORT RequiredExp DESTINATION lib
INCLUDES DESTINATION
@@ -622,6 +625,7 @@ install(
systemlib
testInterfaceIncludeUser
testInterfaceIncludeUser2
testSharedLibArchiveAIX
EXPORT exp
RUNTIME DESTINATION $<1:bin>$<0:/wrong>
LIBRARY DESTINATION $<1:lib>$<0:/wrong> NAMELINK_SKIP
@@ -699,6 +703,7 @@ export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 te
testExeWithPluginHelper testExePluginHelperObj
testMod1 testMod2
testLibPerConfigDest
testSharedLibArchiveAIX
NAMESPACE bld_
APPEND FILE ExportBuildTree.cmake
)

View File

@@ -0,0 +1,10 @@
#if defined(_WIN32) || defined(__CYGWIN__)
# define EXPORT __declspec(dllexport)
#else
# define EXPORT
#endif
EXPORT int testSharedLibArchiveAIX(void)
{
return 0;
}

View File

@@ -68,6 +68,7 @@ target_link_libraries(imp_testExe1
exp_testLib7
exp_testLibCycleA
exp_testLibPerConfigDest
exp_testSharedLibArchiveAIX
exp_testStaticLibWithPlugin
)
@@ -123,6 +124,7 @@ target_link_libraries(imp_testExe1b
bld_testLib7
bld_testLibCycleA
bld_testLibPerConfigDest
bld_testSharedLibArchiveAIX
bld_testStaticLibWithPlugin
)

View File

@@ -11,6 +11,7 @@ extern int testLib7(void);
extern int testLibCycleA1(void);
extern int testLibPerConfigDest(void);
extern int testStaticLibPlugin(void);
extern int testSharedLibArchiveAIX(void);
/* Switch a symbol between debug and optimized builds to make sure the
proper library is found from the testLib4 link interface. */
@@ -26,6 +27,6 @@ int main(void)
return (testLib2() + generated_by_testExe1() + testLib3() + testLib4() +
testLib5() + testLib6() + testLib7() + testLibCycleA1() +
testLibPerConfigDest() + testStaticLibPlugin() +
generated_by_testExe3() + generated_by_testExe4() + testLib4lib() +
testLib4libcfg());
testSharedLibArchiveAIX() + generated_by_testExe3() +
generated_by_testExe4() + testLib4lib() + testLib4libcfg());
}

View File

@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.30)
project(SharedLibraryArchive C)
set(CMAKE_AIX_SHARED_LIBRARY_ARCHIVE 1)
add_library(sla SHARED sla.c)
get_property(aix_sla TARGET sla PROPERTY AIX_SHARED_LIBRARY_ARCHIVE)
if(NOT aix_sla)
message(FATAL_ERROR "AIX_SHARED_LIBRARY_ARCHIVE not initialized on SHARED library")
endif()
add_custom_command(TARGET sla POST_BUILD VERBATIM
COMMAND ${CMAKE_COMMAND} -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -Dsla=$<TARGET_FILE:sla> -P${CMAKE_CURRENT_SOURCE_DIR}/sla-check.cmake
)
add_executable(UseSLA use_sla.c)
get_property(aix_sla TARGET UseSLA PROPERTY AIX_SHARED_LIBRARY_ARCHIVE)
if(aix_sla)
message(FATAL_ERROR "AIX_SHARED_LIBRARY_ARCHIVE initialized on EXECUTABLE")
endif()
target_link_libraries(UseSLA PRIVATE sla)

View File

@@ -0,0 +1,9 @@
if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
if(NOT sla MATCHES [[/libsla\.a]])
message(FATAL_ERROR "sla library does not look like an archive:\n ${sla}")
endif()
execute_process(COMMAND ar t ${sla} OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE sla_members)
if(NOT sla_members MATCHES [[^libsla\.so]])
message(FATAL_ERROR "sla library archive does not have expected members:\n ${sla_members}")
endif()
endif()

View File

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

View File

@@ -0,0 +1,9 @@
#ifdef _WIN32
__declspec(dllimport)
#endif
int sla(void);
int main(void)
{
return sla();
}