Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add post build check to verify that the libs on macOS have the right architecture #163

Merged
merged 11 commits into from
Mar 7, 2022
11 changes: 11 additions & 0 deletions include/vcpkg/base/files.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,17 @@ namespace vcpkg
return !Strings::case_insensitive_ascii_equals(target.extension(), ext);
}
};

struct NotExtensionsCaseInsensitive
{
std::vector<std::string> exts;
bool operator()(const Path& target) const
{
return !std::any_of(exts.begin(), exts.end(), [extension = target.extension()](const auto& ext) {
return Strings::case_insensitive_ascii_equals(extension, ext);
});
}
};
}

VCPKG_FORMAT_AS(vcpkg::Path, vcpkg::StringView);
86 changes: 60 additions & 26 deletions src/vcpkg/postbuildlint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,6 @@ namespace vcpkg::PostBuildLint
std::string actual_arch;
};

#if defined(_WIN32)
static std::string get_actual_architecture(const MachineType& machine_type)
{
switch (machine_type)
Expand All @@ -499,9 +498,7 @@ namespace vcpkg::PostBuildLint
default: return "Machine Type Code = " + std::to_string(static_cast<uint16_t>(machine_type));
}
}
#endif

#if defined(_WIN32)
static void print_invalid_architecture_files(const std::string& expected_architecture,
std::vector<FileAndArch> binaries_with_invalid_architecture)
{
Expand All @@ -519,6 +516,8 @@ namespace vcpkg::PostBuildLint
}
}

#if defined(_WIN32)

static LintStatus check_dll_architecture(const std::string& expected_architecture,
const std::vector<Path>& files,
const Filesystem& fs)
Expand Down Expand Up @@ -551,31 +550,56 @@ namespace vcpkg::PostBuildLint
#endif

static LintStatus check_lib_architecture(const std::string& expected_architecture,
const std::string& cmake_system_name,
const std::vector<Path>& files,
const Filesystem& fs)
{
#if defined(_WIN32)
std::vector<FileAndArch> binaries_with_invalid_architecture;

for (const Path& file : files)
if (cmake_system_name.empty() || cmake_system_name == "Windows" || cmake_system_name == "WindowsStore" ||
cmake_system_name == "MinGW")
{
Checks::check_exit(VCPKG_LINE_INFO,
Strings::case_insensitive_ascii_equals(file.extension(), ".lib"),
"The file extension was not .lib: %s",
file);
const auto machine_types = read_lib_machine_types(fs.open_for_read(file, VCPKG_LINE_INFO));
for (const Path& file : files)
{
Checks::check_exit(VCPKG_LINE_INFO,
Strings::case_insensitive_ascii_equals(file.extension(), ".lib"),
"The file extension was not .lib: %s",
file);
const auto machine_types = read_lib_machine_types(fs.open_for_read(file, VCPKG_LINE_INFO));

// This is zero for folly's debug library
// TODO: Why?
if (machine_types.empty()) return LintStatus::SUCCESS;
// This is zero for folly's debug library
// TODO: Why?
if (machine_types.empty()) break;

Checks::check_exit(
VCPKG_LINE_INFO, machine_types.size() == 1, "Found more than 1 architecture in file %s", file);
Checks::check_exit(
VCPKG_LINE_INFO, machine_types.size() == 1, "Found more than 1 architecture in file %s", file);

const std::string actual_architecture = get_actual_architecture(machine_types.front());
if (expected_architecture != actual_architecture)
const std::string actual_architecture = get_actual_architecture(machine_types.front());
if (expected_architecture != actual_architecture)
{
binaries_with_invalid_architecture.push_back({file, actual_architecture});
}
}
}
else if (cmake_system_name == "Darwin")
{
const auto requested_arch = expected_architecture == "x64" ? "x86_64" : expected_architecture;
for (const Path& file : files)
{
binaries_with_invalid_architecture.push_back({file, actual_architecture});
auto cmd_line = Command("lipo").string_arg("-archs").path_arg(file);
ExitCodeAndOutput ec_data = cmd_execute_and_capture_output(cmd_line);
if (ec_data.exit_code != 0)
{
printf(Color::warning,
"Error: unable to determine the architectures of binary file %s. Running lipo failed "
"with status code %d\n %s",
file,
ec_data.exit_code,
cmd_line.command_line());
}
else if (!Util::Vectors::contains(Strings::split(Strings::trim(ec_data.output), ' '), requested_arch))
{
binaries_with_invalid_architecture.push_back({file, ec_data.output});
}
}
}

Expand All @@ -584,10 +608,6 @@ namespace vcpkg::PostBuildLint
print_invalid_architecture_files(expected_architecture, binaries_with_invalid_architecture);
return LintStatus::PROBLEM_DETECTED;
}
#endif
(void)expected_architecture;
(void)files;
(void)fs;
return LintStatus::SUCCESS;
}

Expand Down Expand Up @@ -1012,10 +1032,23 @@ namespace vcpkg::PostBuildLint
const auto debug_bin_dir = package_dir / "debug" / "bin";
const auto release_bin_dir = package_dir / "bin";

const auto lib_filter = [&pre_build_info]() {
if (pre_build_info.cmake_system_name.empty() || pre_build_info.cmake_system_name == "Windows" ||
pre_build_info.cmake_system_name == "WindowsStore")
{
return NotExtensionsCaseInsensitive{{".lib"}};
}
if (pre_build_info.cmake_system_name == "MinGW")
{
return NotExtensionsCaseInsensitive{{".lib", ".a"}};
}
return NotExtensionsCaseInsensitive{{".so", ".a", ".dylib"}};
}();

std::vector<Path> debug_libs = fs.get_regular_files_recursive(debug_lib_dir, IgnoreErrors{});
Util::erase_remove_if(debug_libs, NotExtensionCaseInsensitive{".lib"});
Util::erase_remove_if(debug_libs, lib_filter);
std::vector<Path> release_libs = fs.get_regular_files_recursive(release_lib_dir, IgnoreErrors{});
Util::erase_remove_if(release_libs, NotExtensionCaseInsensitive{".lib"});
Util::erase_remove_if(release_libs, lib_filter);

if (!pre_build_info.build_type && !build_info.policies.is_enabled(BuildPolicy::MISMATCHED_NUMBER_OF_BINARIES))
error_count += check_matching_debug_and_release_binaries(debug_libs, release_libs);
Expand All @@ -1025,7 +1058,8 @@ namespace vcpkg::PostBuildLint
std::vector<Path> libs;
libs.insert(libs.cend(), debug_libs.cbegin(), debug_libs.cend());
libs.insert(libs.cend(), release_libs.cbegin(), release_libs.cend());
error_count += check_lib_architecture(pre_build_info.target_architecture, libs, fs);
error_count +=
check_lib_architecture(pre_build_info.target_architecture, pre_build_info.cmake_system_name, libs, fs);
}

std::vector<Path> debug_dlls = fs.get_regular_files_recursive(debug_bin_dir, IgnoreErrors{});
Expand Down