mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-06 14:19:59 -05:00
Merge topic 'macos-check-archs'
db409e5e68APPLE: Check if compilers respect CMAKE_OSX_ARCHITECTURES598bc70474file: Add undocumented READ_MACHO subcommand on macOS Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !9492
This commit is contained in:
@@ -99,6 +99,41 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
|
||||
# Load the resulting information strings.
|
||||
if(CMAKE_${lang}_ABI_COMPILED)
|
||||
message(CHECK_PASS "done")
|
||||
if(CMAKE_HOST_APPLE AND CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
file(READ_MACHO "${BIN}" ARCHITECTURES archs CAPTURE_ERROR macho_error) # undocumented file() subcommand
|
||||
if (NOT macho_error)
|
||||
# sort and prune the list of found architectures
|
||||
set(arch_list_sorted ${archs})
|
||||
list(SORT arch_list_sorted)
|
||||
list(REMOVE_DUPLICATES arch_list_sorted)
|
||||
# sort and prune the list of requested architectures
|
||||
set(requested_arch_list ${CMAKE_OSX_ARCHITECTURES})
|
||||
list(SORT requested_arch_list)
|
||||
list(REMOVE_DUPLICATES requested_arch_list)
|
||||
message(CONFIGURE_LOG
|
||||
"Effective list of requested architectures (possibly empty) : \"${requested_arch_list}\"\n"
|
||||
"Effective list of architectures found in the ABI info binary: \"${arch_list_sorted}\"\n")
|
||||
# If all generated architectures were known to READ_MACHO (i.e. libmacho):
|
||||
# Compare requested and found:
|
||||
# - if no architecture(s) were requested explicitly, just check if READ_MACHO returned
|
||||
# an architecture for the ABI info binary.
|
||||
# - otherwise, check if the requested and found lists are equal
|
||||
if(arch_list_sorted MATCHES "unknown")
|
||||
# Rare but not impossible: a host with a toolchain capable of generating binaries with
|
||||
# architectures that the system libmacho is too old to know. Report the found archs as
|
||||
# usual, warn about the unknowns and skip the comparison with CMAKE_OSX_ARCHITECTURES.
|
||||
message(WARNING "The ${lang} compiler generates universal binaries with at least 1 architecture not known to the host")
|
||||
elseif(requested_arch_list AND arch_list_sorted
|
||||
AND NOT "${requested_arch_list}" STREQUAL "${arch_list_sorted}")
|
||||
# inform the user of the mismatch but show the raw input and output lists
|
||||
message(FATAL_ERROR
|
||||
"The ${lang} compiler targets architectures:\n"
|
||||
" \"${archs}\"\n"
|
||||
"but CMAKE_OSX_ARCHITECTURES is\n"
|
||||
" \"${CMAKE_OSX_ARCHITECTURES}\"\n")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(SET CMP0159 NEW) # file(STRINGS) with REGEX updates CMAKE_MATCH_<n>
|
||||
file(STRINGS "${BIN}" ABI_STRINGS LIMIT_COUNT 32 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]")
|
||||
|
||||
@@ -557,6 +557,8 @@ add_library(
|
||||
cmFLTKWrapUICommand.h
|
||||
cmFileCommand.cxx
|
||||
cmFileCommand.h
|
||||
cmFileCommand_ReadMacho.cxx
|
||||
cmFileCommand_ReadMacho.h
|
||||
cmFindBase.cxx
|
||||
cmFindBase.h
|
||||
cmFindCommon.cxx
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "cmELF.h"
|
||||
#include "cmExecutionStatus.h"
|
||||
#include "cmFSPermissions.h"
|
||||
#include "cmFileCommand_ReadMacho.h"
|
||||
#include "cmFileCopier.h"
|
||||
#include "cmFileInstaller.h"
|
||||
#include "cmFileLockPool.h"
|
||||
@@ -3965,6 +3966,7 @@ bool cmFileCommand(std::vector<std::string> const& args,
|
||||
{ "RPATH_CHECK"_s, HandleRPathCheckCommand },
|
||||
{ "RPATH_REMOVE"_s, HandleRPathRemoveCommand },
|
||||
{ "READ_ELF"_s, HandleReadElfCommand },
|
||||
{ "READ_MACHO"_s, HandleReadMachoCommand },
|
||||
{ "REAL_PATH"_s, HandleRealPathCommand },
|
||||
{ "RELATIVE_PATH"_s, HandleRelativePathCommand },
|
||||
{ "TO_CMAKE_PATH"_s, HandleCMakePathCommand },
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#include "cmFileCommand_ReadMacho.h"
|
||||
|
||||
#include "cmArgumentParser.h"
|
||||
#include "cmExecutionStatus.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmRange.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
#if defined(CMake_USE_MACH_PARSER)
|
||||
# include "cmMachO.h"
|
||||
#endif
|
||||
|
||||
#include <cmext/string_view>
|
||||
|
||||
bool HandleReadMachoCommand(std::vector<std::string> const& args,
|
||||
cmExecutionStatus& status)
|
||||
{
|
||||
if (args.size() < 4) {
|
||||
status.SetError("READ_MACHO must be called with at least three additional "
|
||||
"arguments.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string const& fileNameArg = args[1];
|
||||
|
||||
struct Arguments
|
||||
{
|
||||
std::string Architectures;
|
||||
std::string Error;
|
||||
};
|
||||
|
||||
static auto const parser =
|
||||
cmArgumentParser<Arguments>{}
|
||||
.Bind("ARCHITECTURES"_s, &Arguments::Architectures)
|
||||
.Bind("CAPTURE_ERROR"_s, &Arguments::Error);
|
||||
Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2),
|
||||
/*unparsedArguments=*/nullptr);
|
||||
|
||||
if (!arguments.Architectures.empty()) {
|
||||
// always return something sensible for ARCHITECTURES
|
||||
status.GetMakefile().AddDefinition(arguments.Architectures, "unknown"_s);
|
||||
}
|
||||
if (!cmSystemTools::FileExists(fileNameArg, true)) {
|
||||
if (arguments.Error.empty()) {
|
||||
status.SetError(cmStrCat("READ_MACHO given FILE \"", fileNameArg,
|
||||
"\" that does not exist."));
|
||||
return false;
|
||||
}
|
||||
status.GetMakefile().AddDefinition(
|
||||
arguments.Error, cmStrCat(fileNameArg, " does not exist"));
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(CMake_USE_MACH_PARSER)
|
||||
cmMachO macho(fileNameArg.c_str());
|
||||
if (!macho) {
|
||||
if (arguments.Error.empty()) {
|
||||
status.SetError(cmStrCat("READ_MACHO given FILE:\n ", fileNameArg,
|
||||
"\nthat is not a valid Macho-O file."));
|
||||
return false;
|
||||
}
|
||||
status.GetMakefile().AddDefinition(
|
||||
arguments.Error, cmStrCat(fileNameArg, " is not a valid Macho-O file"));
|
||||
return true;
|
||||
} else if (!macho.GetErrorMessage().empty()) {
|
||||
if (arguments.Error.empty()) {
|
||||
status.SetError(cmStrCat(
|
||||
"READ_MACHO given FILE:\n ", fileNameArg,
|
||||
"\nthat is not a supported Macho-O file: ", macho.GetErrorMessage()));
|
||||
return false;
|
||||
}
|
||||
status.GetMakefile().AddDefinition(
|
||||
arguments.Error,
|
||||
cmStrCat(fileNameArg,
|
||||
" is not a supported Macho-O file: ", macho.GetErrorMessage()));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string output;
|
||||
|
||||
if (!arguments.Architectures.empty()) {
|
||||
auto archs = macho.GetArchitectures();
|
||||
output = cmJoin(archs, ";");
|
||||
|
||||
// Save the output in a makefile variable.
|
||||
status.GetMakefile().AddDefinition(arguments.Architectures, output);
|
||||
}
|
||||
#else
|
||||
if (arguments.Error.empty()) {
|
||||
status.SetError("READ_MACHO support not available on this platform.");
|
||||
return false;
|
||||
}
|
||||
status.GetMakefile().AddDefinition(
|
||||
arguments.Error, "READ_MACHO support not available on this platform.");
|
||||
#endif // CMake_USE_MACH_PARSER
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class cmExecutionStatus;
|
||||
|
||||
bool HandleReadMachoCommand(std::vector<std::string> const& args,
|
||||
cmExecutionStatus& status);
|
||||
+51
-4
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/memory>
|
||||
|
||||
@@ -13,8 +12,12 @@
|
||||
#include "cmAlgorithms.h"
|
||||
|
||||
// Include the Mach-O format information system header.
|
||||
#include <mach-o/arch.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <mach-o/loader.h>
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000
|
||||
# include <mach-o/utils.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
||||
@@ -115,12 +118,15 @@ public:
|
||||
return v;
|
||||
}
|
||||
|
||||
struct cmMachO::MachHeader mach_header() const { return MachHeader; }
|
||||
|
||||
protected:
|
||||
bool read_load_commands(uint32_t ncmds, uint32_t sizeofcmds,
|
||||
cmsys::ifstream& fin);
|
||||
|
||||
bool Swap;
|
||||
std::vector<RawLoadCommand> LoadCommands;
|
||||
struct cmMachO::MachHeader MachHeader;
|
||||
};
|
||||
|
||||
// Implementation for reading Mach-O header and load commands.
|
||||
@@ -138,9 +144,11 @@ public:
|
||||
if (!read(fin, this->Header)) {
|
||||
return false;
|
||||
}
|
||||
this->Header.cputype = swap(this->Header.cputype);
|
||||
this->Header.cpusubtype = swap(this->Header.cpusubtype);
|
||||
this->Header.filetype = swap(this->Header.filetype);
|
||||
// swap the header data and export a (potentially) useful subset via the
|
||||
// parent class.
|
||||
this->MachHeader.CpuType = swap(this->Header.cputype);
|
||||
this->MachHeader.CpuSubType = swap(this->Header.cpusubtype);
|
||||
this->MachHeader.FileType = swap(this->Header.filetype);
|
||||
this->Header.ncmds = swap(this->Header.ncmds);
|
||||
this->Header.sizeofcmds = swap(this->Header.sizeofcmds);
|
||||
this->Header.flags = swap(this->Header.flags);
|
||||
@@ -311,6 +319,9 @@ bool cmMachOInternal::read_mach_o(uint32_t file_offset)
|
||||
cmMachO::cmMachO(const char* fname)
|
||||
: Internal(cm::make_unique<cmMachOInternal>(fname))
|
||||
{
|
||||
for (const auto& m : this->Internal->MachOList) {
|
||||
Headers.push_back(m->mach_header());
|
||||
}
|
||||
}
|
||||
|
||||
cmMachO::~cmMachO() = default;
|
||||
@@ -355,3 +366,39 @@ bool cmMachO::GetInstallName(std::string& install_name)
|
||||
void cmMachO::PrintInfo(std::ostream& /*os*/) const
|
||||
{
|
||||
}
|
||||
|
||||
cmMachO::StringList cmMachO::GetArchitectures() const
|
||||
{
|
||||
cmMachO::StringList archs;
|
||||
if (Valid() && !this->Headers.empty()) {
|
||||
for (const auto& header : this->Headers) {
|
||||
const char* archName = "unknown";
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000
|
||||
if (__builtin_available(macOS 13.0, *)) {
|
||||
archName = (header.CpuType & CPU_TYPE_ARM)
|
||||
? macho_arch_name_for_cpu_type(header.CpuType, header.CpuSubType)
|
||||
: macho_arch_name_for_cpu_type(header.CpuType, CPU_SUBTYPE_MULTIPLE);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
#if defined __clang__
|
||||
# define CM_MACOS_DEPRECATED_NXGetArchInfoFromCpuType
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
const NXArchInfo* archInfo = (header.CpuType & CPU_TYPE_ARM)
|
||||
? NXGetArchInfoFromCpuType(header.CpuType, header.CpuSubType)
|
||||
: NXGetArchInfoFromCpuType(header.CpuType, CPU_SUBTYPE_MULTIPLE);
|
||||
#ifdef CM_MACOS_DEPRECATED_NXGetArchInfoFromCpuType
|
||||
# undef CM_MACOS_DEPRECATED_NXGetArchInfoFromCpuType
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
if (archInfo) {
|
||||
archName = archInfo->name;
|
||||
}
|
||||
}
|
||||
archs.push_back(archName);
|
||||
}
|
||||
}
|
||||
return archs;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <mach/machine.h>
|
||||
|
||||
#if !defined(CMake_USE_MACH_PARSER)
|
||||
# error "This file may be included only if CMake_USE_MACH_PARSER is enabled."
|
||||
@@ -20,6 +23,16 @@ class cmMachOInternal;
|
||||
class cmMachO
|
||||
{
|
||||
public:
|
||||
struct MachHeader
|
||||
{
|
||||
cpu_type_t CpuType;
|
||||
cpu_subtype_t CpuSubType;
|
||||
uint32_t FileType;
|
||||
};
|
||||
class StringList : public std::vector<std::string>
|
||||
{
|
||||
};
|
||||
|
||||
/** Construct with the name of the Mach-O input file to parse. */
|
||||
cmMachO(const char* fname);
|
||||
|
||||
@@ -38,8 +51,17 @@ public:
|
||||
/** Print human-readable information about the Mach-O file. */
|
||||
void PrintInfo(std::ostream& os) const;
|
||||
|
||||
/** Get the architectural header(s) from the Mach-O file. */
|
||||
std::vector<struct MachHeader> GetHeaders() const { return this->Headers; }
|
||||
|
||||
/** Get a list of the recognized architectures present in the Mach-O file
|
||||
* in the order in which they are found.
|
||||
*/
|
||||
StringList GetArchitectures() const;
|
||||
|
||||
private:
|
||||
friend class cmMachOInternal;
|
||||
bool Valid() const;
|
||||
std::unique_ptr<cmMachOInternal> Internal;
|
||||
std::vector<struct MachHeader> Headers;
|
||||
};
|
||||
|
||||
@@ -353,6 +353,7 @@ CMAKE_CXX_SOURCES="\
|
||||
cmExprParserHelper \
|
||||
cmExternalMakefileProjectGenerator \
|
||||
cmFileCommand \
|
||||
cmFileCommand_ReadMacho \
|
||||
cmFileCopier \
|
||||
cmFileInstaller \
|
||||
cmFileSet \
|
||||
@@ -521,6 +522,12 @@ CMAKE_CXX_SOURCES="\
|
||||
cm_fileno \
|
||||
"
|
||||
|
||||
if ${cmake_system_darwin}; then
|
||||
CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES}\
|
||||
cmMachO \
|
||||
"
|
||||
fi
|
||||
|
||||
if ${cmake_system_mingw}; then
|
||||
CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES}\
|
||||
cmGlobalMSYSMakefileGenerator \
|
||||
@@ -1669,6 +1676,10 @@ else
|
||||
cmake_report cmConfigure.h${_tmp} "#define CMAKE_BOOTSTRAP_MAKEFILES"
|
||||
fi
|
||||
|
||||
if ${cmake_system_darwin}; then
|
||||
cmake_report cmConfigure.h${_tmp} "#define CMake_USE_MACH_PARSER"
|
||||
fi
|
||||
|
||||
if ${cmake_system_mingw}; then
|
||||
cmake_report cmConfigure.h${_tmp} "#if defined(_WIN32) && !defined(NOMINMAX)"
|
||||
cmake_report cmConfigure.h${_tmp} "# define NOMINMAX"
|
||||
|
||||
Reference in New Issue
Block a user