From acd0bece4f1589e013b9d04fc80a54efb4381625 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Sun, 11 Dec 2022 21:05:13 -0800 Subject: [PATCH 01/33] Rip out all uses of dumpbin for looking at DLLs. --- include/vcpkg/base/cofffilereader.h | 40 +++++- src/vcpkg/base/cofffilereader.cpp | 48 ++++++- src/vcpkg/postbuildlint.cpp | 194 +++++++++++++++------------- 3 files changed, 184 insertions(+), 98 deletions(-) diff --git a/include/vcpkg/base/cofffilereader.h b/include/vcpkg/base/cofffilereader.h index e195713a6c..d175c60fa9 100644 --- a/include/vcpkg/base/cofffilereader.h +++ b/include/vcpkg/base/cofffilereader.h @@ -37,6 +37,26 @@ namespace vcpkg uint32_t base_of_code; }; + enum class DllCharacteristics : uint16_t + { + HighEntropyVA = 0x0020, + DynamicBase = 0x0040, + ForceIntegrity = 0x0080, + NxCompat = 0x0100, + NoIsolation = 0x0200, + NoSeh = 0x0400, + NoBind = 0x0800, + AppContainer = 0x1000, + WdmDriver = 0x2000, + GuardCF = 0x4000, + TSAware = 0x8000 + }; + + constexpr bool operator&(DllCharacteristics lhs, DllCharacteristics rhs) noexcept + { + return (static_cast(lhs) & static_cast(rhs)) != 0; + } + struct UniquePEOptionalHeaders { uint32_t base_of_data; @@ -54,7 +74,7 @@ namespace vcpkg uint32_t size_of_headers; uint32_t checksum; uint16_t subsystem; - uint16_t dll_characteristics; + DllCharacteristics dll_characteristics; uint32_t size_of_stack_reserve; uint32_t size_of_stack_commit; uint32_t size_of_heap_reserve; @@ -79,7 +99,7 @@ namespace vcpkg uint32_t size_of_headers; uint32_t checksum; uint16_t subsystem; - uint16_t dll_characteristics; + DllCharacteristics dll_characteristics; uint64_t size_of_stack_reserve; uint64_t size_of_stack_commit; uint64_t size_of_heap_reserve; @@ -108,6 +128,21 @@ namespace vcpkg uint32_t characteristics; }; + struct ExportDirectoryTable + { + uint32_t export_flags; + uint32_t timestamp; + uint16_t major_version; + uint16_t minor_version; + uint32_t name_rva; + uint32_t ordinal_base; + uint32_t address_table_entries; + uint32_t number_of_name_pointers; + uint32_t export_address_table_rva; + uint32_t name_pointer_rva; + uint32_t ordinal_table_rva; + }; + struct ImportDirectoryTableEntry { uint32_t import_lookup_table_rva; @@ -284,6 +319,7 @@ namespace vcpkg }; ExpectedL try_read_dll_metadata(ReadFilePointer& f); + ExpectedL try_read_if_dll_has_exports(const DllMetadata& dll, ReadFilePointer& f); ExpectedL> try_read_dll_imported_dll_names(const DllMetadata& dll, ReadFilePointer& f); std::vector read_lib_machine_types(const ReadFilePointer& f); } diff --git a/src/vcpkg/base/cofffilereader.cpp b/src/vcpkg/base/cofffilereader.cpp index d25b070387..309b0987fa 100644 --- a/src/vcpkg/base/cofffilereader.cpp +++ b/src/vcpkg/base/cofffilereader.cpp @@ -129,7 +129,7 @@ namespace // seeks the file `f` to the location in the file denoted by `rva`; // returns the remaining size of data in the section - ExpectedL try_seek_to_rva(const DllMetadata& metadata, ReadFilePointer& f, uint32_t rva) + ExpectedL try_seek_to_rva(const DllMetadata& metadata, ReadFilePointer& f, uint32_t rva) { // The PE spec says that the sections have to be sorted by virtual_address and // contiguous, but this does not assume that for paranoia reasons. @@ -143,7 +143,7 @@ namespace const auto start_offset_within_section = rva - section.virtual_address; const auto file_pointer = start_offset_within_section + section.pointer_to_raw_data; - const size_t leftover = section.size_of_raw_data - start_offset_within_section; + const uint32_t leftover = section.size_of_raw_data - start_offset_within_section; return f.try_seek_to(file_pointer).map([=](Unit) { return leftover; }); } @@ -204,11 +204,27 @@ namespace return std::move(maybe_remaining_size).error(); } + ExpectedL try_read_struct_from_rva( + const DllMetadata& metadata, ReadFilePointer& f, void* target, uint32_t rva, uint32_t size) + { + return try_seek_to_rva(metadata, f, rva).then([&](uint32_t maximum_size) -> ExpectedL { + if (maximum_size >= size) + { + return f.try_read_all(target, size); + } + + return f.try_read_all(target, maximum_size).map([&](Unit) { + ::memset(static_cast(target) + maximum_size, 0, size - maximum_size); + return Unit{}; + }); + }); + } + ExpectedL try_read_ntbs_from_rva(const DllMetadata& metadata, ReadFilePointer& f, uint32_t rva) { // Note that maximum_size handles the case that size_of_raw_data < virtual_size, where the loader // inserts the null(s). - return try_seek_to_rva(metadata, f, rva).then([&](size_t maximum_size) -> ExpectedL { + return try_seek_to_rva(metadata, f, rva).then([&](uint32_t maximum_size) -> ExpectedL { std::string result; for (;;) { @@ -445,6 +461,32 @@ namespace vcpkg return result; } + ExpectedL try_read_if_dll_has_exports(const DllMetadata& dll, ReadFilePointer& f) + { + if (dll.data_directories.size() < 1) + { + Debug::print("No export directory\n"); + return false; + } + + const auto& export_data_directory = dll.data_directories[0]; + if (export_data_directory.virtual_address == 0) + { + Debug::print("Null export directory.\n"); + return false; + } + + ExportDirectoryTable export_directory_table; + auto export_read_result = try_read_struct_from_rva( + dll, f, &export_directory_table, export_data_directory.virtual_address, sizeof(export_directory_table)); + if (!export_read_result.has_value()) + { + return std::move(export_read_result).error(); + } + + return export_directory_table.address_table_entries != 0; + } + ExpectedL> try_read_dll_imported_dll_names(const DllMetadata& dll, ReadFilePointer& f) { if (dll.data_directories.size() < 2) diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index c628098ca0..096091dc95 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -384,30 +384,72 @@ namespace vcpkg::PostBuildLint return LintStatus::SUCCESS; } + struct PostBuildCheckDllData + { + Path path; + MachineType machine_type; + bool is_arm64_ec; + bool has_exports; + bool has_appcontainer; + std::vector dependencies; + }; + + static ExpectedL try_load_dll_data(const Filesystem& fs, const Path& path) + { + auto maybe_file = fs.try_open_for_read(path); + auto file = maybe_file.get(); + if (!file) + { + return std::move(maybe_file).error(); + } + + auto maybe_metadata = try_read_dll_metadata(*file); + auto metadata = maybe_metadata.get(); + if (!metadata) + { + return std::move(maybe_metadata).error(); + } + + bool has_exports = try_read_if_dll_has_exports(*metadata, *file).value_or(true); + + bool has_appcontainer; + switch (metadata->pe_type) + { + case PEType::PE32: + has_appcontainer = metadata->pe_headers.dll_characteristics & DllCharacteristics::AppContainer; + break; + case PEType::PE32Plus: + has_appcontainer = metadata->pe_plus_headers.dll_characteristics & DllCharacteristics::AppContainer; + break; + default: Checks::unreachable(VCPKG_LINE_INFO); + } + + auto maybe_dependencies = try_read_dll_imported_dll_names(*metadata, *file); + auto dependencies = maybe_dependencies.get(); + if (!dependencies) + { + return std::move(maybe_dependencies).error(); + } + + return PostBuildCheckDllData{path, + metadata->get_machine_type(), + metadata->is_arm64_ec(), + has_exports, + has_appcontainer, + std::move(*dependencies)}; + } + static LintStatus check_exports_of_dlls(const BuildPolicies& policies, - const std::vector& dlls, - const Path& dumpbin_exe) + const std::vector& dlls) { if (policies.is_enabled(BuildPolicy::DLLS_WITHOUT_EXPORTS)) return LintStatus::SUCCESS; std::vector dlls_with_no_exports; - for (const Path& dll : dlls) + for (const PostBuildCheckDllData& dll_data : dlls) { - auto cmd_line = Command(dumpbin_exe).string_arg("/exports").string_arg(dll); - const auto maybe_output = flatten_out(cmd_execute_and_capture_output(cmd_line), "dumpbin"); - if (const auto output = maybe_output.get()) - { - if (output->find("ordinal hint RVA name") == std::string::npos) - { - dlls_with_no_exports.push_back(dll); - } - } - else + if (!dll_data.has_exports) { - Checks::msg_exit_with_message(VCPKG_LINE_INFO, - msg::format(msgCommandFailed, msg::command_line = cmd_line.command_line()) - .append_raw('\n') - .append(maybe_output.error())); + dlls_with_no_exports.push_back(dll_data.path); } } @@ -422,8 +464,7 @@ namespace vcpkg::PostBuildLint } static LintStatus check_uwp_bit_of_dlls(const std::string& expected_system_name, - const std::vector& dlls, - const Path dumpbin_exe) + const std::vector& dlls) { if (expected_system_name != "WindowsStore") { @@ -431,23 +472,11 @@ namespace vcpkg::PostBuildLint } std::vector dlls_with_improper_uwp_bit; - for (const Path& dll : dlls) + for (const PostBuildCheckDllData& dll_data : dlls) { - auto cmd_line = Command(dumpbin_exe).string_arg("/headers").string_arg(dll); - const auto maybe_output = flatten_out(cmd_execute_and_capture_output(cmd_line), "dumpbin"); - if (const auto output = maybe_output.get()) - { - if (output->find("App Container") == std::string::npos) - { - dlls_with_improper_uwp_bit.push_back(dll); - } - } - else + if (!dll_data.has_appcontainer) { - Checks::msg_exit_with_message(VCPKG_LINE_INFO, - msg::format(msgCommandFailed, msg::command_line = cmd_line.command_line()) - .append_raw('\n') - .append(maybe_output.error())); + dlls_with_improper_uwp_bit.push_back(dll_data.path); } } @@ -496,41 +525,25 @@ namespace vcpkg::PostBuildLint } } -#if defined(_WIN32) static LintStatus check_dll_architecture(const std::string& expected_architecture, - const std::vector& files, - const Filesystem& fs) + const std::vector& dlls) { std::vector binaries_with_invalid_architecture; - for (const Path& file : files) + for (const PostBuildCheckDllData& dll_data : dlls) { - if (!Strings::case_insensitive_ascii_equals(file.extension(), ".dll")) + const std::string actual_architecture = get_actual_architecture(dll_data.machine_type); + if (expected_architecture == "arm64ec") { - continue; - } - - auto maybe_opened = fs.try_open_for_read(file); - if (const auto opened = maybe_opened.get()) - { - auto maybe_metadata = try_read_dll_metadata(*opened); - if (auto* metadata = maybe_metadata.get()) + if (actual_architecture != "x64" || !dll_data.is_arm64_ec) { - const auto machine_type = metadata->get_machine_type(); - const std::string actual_architecture = get_actual_architecture(machine_type); - if (expected_architecture == "arm64ec") - { - if (actual_architecture != "x64" || !metadata->is_arm64_ec()) - { - binaries_with_invalid_architecture.push_back({file, actual_architecture}); - } - } - else if (expected_architecture != actual_architecture) - { - binaries_with_invalid_architecture.push_back({file, actual_architecture}); - } + binaries_with_invalid_architecture.push_back({dll_data.path, actual_architecture}); } } + else if (expected_architecture != actual_architecture) + { + binaries_with_invalid_architecture.push_back({dll_data.path, actual_architecture}); + } } if (!binaries_with_invalid_architecture.empty()) @@ -541,7 +554,6 @@ namespace vcpkg::PostBuildLint return LintStatus::SUCCESS; } -#endif static LintStatus check_lib_architecture(const std::string& expected_architecture, const std::string& cmake_system_name, @@ -902,38 +914,25 @@ namespace vcpkg::PostBuildLint OutdatedDynamicCrt outdated_crt; }; - static LintStatus check_outdated_crt_linkage_of_dlls(const std::vector& dlls, - const Path& dumpbin_exe, + static LintStatus check_outdated_crt_linkage_of_dlls(const std::vector& dlls, const BuildInfo& build_info, const PreBuildInfo& pre_build_info) { if (build_info.policies.is_enabled(BuildPolicy::ALLOW_OBSOLETE_MSVCRT)) return LintStatus::SUCCESS; + const auto outdated_crts = get_outdated_dynamic_crts(pre_build_info.platform_toolset); std::vector dlls_with_outdated_crt; - for (const Path& dll : dlls) + for (const PostBuildCheckDllData& dll_data : dlls) { - auto cmd_line = Command(dumpbin_exe).string_arg("/dependents").string_arg(dll); - const auto maybe_output = flatten_out(cmd_execute_and_capture_output(cmd_line), "dumpbin"); - if (const auto output = maybe_output.get()) + for (const OutdatedDynamicCrt& outdated_crt : outdated_crts) { - for (const OutdatedDynamicCrt& outdated_crt : - get_outdated_dynamic_crts(pre_build_info.platform_toolset)) + if (Util::Vectors::contains(dll_data.dependencies, outdated_crt.name)) { - if (Strings::case_insensitive_ascii_contains(*output, outdated_crt.name)) - { - dlls_with_outdated_crt.push_back({dll, outdated_crt}); - break; - } + dlls_with_outdated_crt.push_back({dll_data.path, outdated_crt}); + break; } } - else - { - Checks::msg_exit_with_message(VCPKG_LINE_INFO, - msg::format(msgCommandFailed, msg::command_line = cmd_line.command_line()) - .append_raw('\n') - .append_raw(maybe_output.error())); - } } if (!dlls_with_outdated_crt.empty()) @@ -1055,23 +1054,32 @@ namespace vcpkg::PostBuildLint error_count += check_lib_files_are_available_if_dlls_are_available( build_info.policies, release_libs.size(), release_dlls.size(), release_lib_dir); - std::vector dlls; - dlls.insert(dlls.cend(), debug_dlls.cbegin(), debug_dlls.cend()); - dlls.insert(dlls.cend(), release_dlls.cbegin(), release_dlls.cend()); + std::vector dlls; + dlls.reserve(debug_dlls.size() + release_dlls.size()); + for (const Path& dll : debug_dlls) + { + auto maybe_dll_data = try_load_dll_data(fs, dll); + if (const auto dll_data = maybe_dll_data.get()) + { + dlls.emplace_back(std::move(*dll_data)); + } + } - if (!toolset.dumpbin.empty() && !build_info.policies.is_enabled(BuildPolicy::SKIP_DUMPBIN_CHECKS)) + for (const Path& dll : release_dlls) { - error_count += check_exports_of_dlls(build_info.policies, dlls, toolset.dumpbin); - error_count += check_uwp_bit_of_dlls(pre_build_info.cmake_system_name, dlls, toolset.dumpbin); - error_count += - check_outdated_crt_linkage_of_dlls(dlls, toolset.dumpbin, build_info, pre_build_info); + auto maybe_dll_data = try_load_dll_data(fs, dll); + if (const auto dll_data = maybe_dll_data.get()) + { + dlls.emplace_back(std::move(*dll_data)); + } } -#if defined(_WIN32) - error_count += check_dll_architecture(pre_build_info.target_architecture, dlls, fs); -#endif - break; + error_count += check_exports_of_dlls(build_info.policies, dlls); + error_count += check_uwp_bit_of_dlls(pre_build_info.cmake_system_name, dlls); + error_count += check_outdated_crt_linkage_of_dlls(dlls, build_info, pre_build_info); + error_count += check_dll_architecture(pre_build_info.target_architecture, dlls); } + break; case LinkageType::STATIC: { auto dlls = release_dlls; From d3e9e18c63de01a7315dfb2c60e001dc8fd6ff93 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 14 Dec 2022 14:07:55 -0600 Subject: [PATCH 02/33] Add e2e test for no exports check. --- .../CMakeLists.txt | 22 +++++++++++++++++++ .../portfile.cmake | 12 ++++++++++ .../vcpkg.json | 10 +++++++++ .../post-build-checks.ps1 | 13 +++++++++++ 4 files changed, 57 insertions(+) create mode 100644 azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/CMakeLists.txt create mode 100644 azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/portfile.cmake create mode 100644 azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/vcpkg.json create mode 100644 azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 diff --git a/azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/CMakeLists.txt b/azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/CMakeLists.txt new file mode 100644 index 0000000000..3a63e6a73e --- /dev/null +++ b/azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.24) +project(vcpkg-internal-dll-with-no-exports LANGUAGES C) +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test.c" [[ #include +BOOLEAN WINAPI DllMain(HINSTANCE hDllHandle, DWORD nReason, LPVOID Reserved) +{ + (void)Reserved; + if (nReason == DLL_PROCESS_ATTACH) { + DisableThreadLibraryCalls( hDllHandle ); + } + + return TRUE; +} +]]) + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test.h" [[ + // empty test header +]]) + +add_library(no_exports "${CMAKE_CURRENT_BINARY_DIR}/test.c") +include(GNUInstallDirs) +install(TARGETS no_exports) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/test.c" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") diff --git a/azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/portfile.cmake b/azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/portfile.cmake new file mode 100644 index 0000000000..400e965ec8 --- /dev/null +++ b/azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/portfile.cmake @@ -0,0 +1,12 @@ +SET(VCPKG_POLICY_DLLS_WITHOUT_LIBS enabled) +file(MAKE_DIRECTORY "${CURRENT_BUILDTREES_DIR}/src") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt" DESTINATION "${CURRENT_BUILDTREES_DIR}/src") +vcpkg_cmake_configure(SOURCE_PATH "${CURRENT_BUILDTREES_DIR}/src") +vcpkg_cmake_install() +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share/${PORT}") +file(REMOVE_RECURSE + "${CURRENT_PACKAGES_DIR}/debug/include" + "${CURRENT_PACKAGES_DIR}/debug/lib" + "${CURRENT_PACKAGES_DIR}/lib") +file(TOUCH "${CURRENT_PACKAGES_DIR}/share/${PORT}/copyright") diff --git a/azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/vcpkg.json b/azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/vcpkg.json new file mode 100644 index 0000000000..721a3a90f1 --- /dev/null +++ b/azure-pipelines/e2e_ports/vcpkg-internal-dll-with-no-exports/vcpkg.json @@ -0,0 +1,10 @@ +{ + "name": "vcpkg-internal-dll-with-no-exports", + "version": "1.0.0", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + } + ] +} diff --git a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 new file mode 100644 index 0000000000..dadbad0e60 --- /dev/null +++ b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 @@ -0,0 +1,13 @@ +. $PSScriptRoot/../end-to-end-tests-prelude.ps1 + +if (-not $IsWindows) { + return +} + +$buildOutput = Run-VcpkgAndCaptureOutput @commonArgs install --overlay-ports="$PSScriptRoot/../e2e_ports" vcpkg-internal-dll-with-no-exports --no-binarycaching +$hasDebugDll = $buildOutput -match "packages/vcpkg-internal-dll-with-no-exports_$Triplet/debug/bin/no_exports\.dll" +$hasReleaseDll = $buildOutput -match "packages/vcpkg-internal-dll-with-no-exports_$Triplet/bin/no_exports\.dll" +$hasSet = $buildOutput -match 'set\(VCPKG_POLICY_DLLS_WITHOUT_EXPORTS enabled\)' +if (-not $hasDebugDll -or -not $hasReleaseDll -or -not $hasSet) { + throw "Did not detect DLLs with no exports." +} From f1fe1c02151094d46fcbc665a3b87f6173f3a0d2 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 14 Dec 2022 16:32:08 -0600 Subject: [PATCH 03/33] Add end to end tests for DLLs with wrong arch and no appcontainer. Also fix duplicated UWP message and the wrong slashes being printed in file paths. --- .../test-dll-port-template/build.cmd | 4 ++ .../test-dll-port-template/portfile.cmake | 14 ++++ .../e2e_assets/test-dll-port-template/test.c | 17 +++++ .../test-dll-port-template/test.def | 4 ++ .../e2e_assets/test-dll-port-template/test.h | 1 + .../test-dll-port-template/vcpkg.json | 4 ++ .../post-build-checks.ps1 | 64 +++++++++++++++++-- src/vcpkg/base/files.cpp | 12 ++-- src/vcpkg/postbuildlint.cpp | 8 ++- 9 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 azure-pipelines/e2e_assets/test-dll-port-template/build.cmd create mode 100644 azure-pipelines/e2e_assets/test-dll-port-template/portfile.cmake create mode 100644 azure-pipelines/e2e_assets/test-dll-port-template/test.c create mode 100644 azure-pipelines/e2e_assets/test-dll-port-template/test.def create mode 100644 azure-pipelines/e2e_assets/test-dll-port-template/test.h create mode 100644 azure-pipelines/e2e_assets/test-dll-port-template/vcpkg.json diff --git a/azure-pipelines/e2e_assets/test-dll-port-template/build.cmd b/azure-pipelines/e2e_assets/test-dll-port-template/build.cmd new file mode 100644 index 0000000000..4f4b194703 --- /dev/null +++ b/azure-pipelines/e2e_assets/test-dll-port-template/build.cmd @@ -0,0 +1,4 @@ +mkdir "%~dp0debug" +mkdir "%~dp0release" +cl /EHsc /MDd "%~dp0test.c" "%~dp0test.def" /Fe"%~dp0debug\test_dll.dll" /link /DLL +cl /EHsc /MD "%~dp0test.c" "%~dp0test.def" /Fe"%~dp0release\test_dll.dll" /link /DLL diff --git a/azure-pipelines/e2e_assets/test-dll-port-template/portfile.cmake b/azure-pipelines/e2e_assets/test-dll-port-template/portfile.cmake new file mode 100644 index 0000000000..a474519fd3 --- /dev/null +++ b/azure-pipelines/e2e_assets/test-dll-port-template/portfile.cmake @@ -0,0 +1,14 @@ +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/bin") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/lib") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug/bin") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug/lib") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/include") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share/${PORT}") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/debug/test_dll.dll" DESTINATION "${CURRENT_PACKAGES_DIR}/debug/bin") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/debug/test_dll.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/debug/lib") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/release/test_dll.dll" DESTINATION "${CURRENT_PACKAGES_DIR}/bin") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/release/test_dll.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/lib") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/test.h" DESTINATION "${CURRENT_PACKAGES_DIR}/include") +file(TOUCH "${CURRENT_PACKAGES_DIR}/share/${PORT}/copyright") diff --git a/azure-pipelines/e2e_assets/test-dll-port-template/test.c b/azure-pipelines/e2e_assets/test-dll-port-template/test.c new file mode 100644 index 0000000000..69fc354ef0 --- /dev/null +++ b/azure-pipelines/e2e_assets/test-dll-port-template/test.c @@ -0,0 +1,17 @@ +#include +#include + +BOOLEAN WINAPI DllMain(HINSTANCE hDllHandle, DWORD nReason, LPVOID Reserved) +{ + (void)Reserved; + if (nReason == DLL_PROCESS_ATTACH) { + DisableThreadLibraryCalls( hDllHandle ); + } + + return TRUE; +} + +int __cdecl export_me() { + puts("You called the exported function!"); + return 42; +} diff --git a/azure-pipelines/e2e_assets/test-dll-port-template/test.def b/azure-pipelines/e2e_assets/test-dll-port-template/test.def new file mode 100644 index 0000000000..aa9fb49c31 --- /dev/null +++ b/azure-pipelines/e2e_assets/test-dll-port-template/test.def @@ -0,0 +1,4 @@ +LIBRARY test_dll + +EXPORTS +export_me diff --git a/azure-pipelines/e2e_assets/test-dll-port-template/test.h b/azure-pipelines/e2e_assets/test-dll-port-template/test.h new file mode 100644 index 0000000000..10d2052384 --- /dev/null +++ b/azure-pipelines/e2e_assets/test-dll-port-template/test.h @@ -0,0 +1 @@ + // empty test header diff --git a/azure-pipelines/e2e_assets/test-dll-port-template/vcpkg.json b/azure-pipelines/e2e_assets/test-dll-port-template/vcpkg.json new file mode 100644 index 0000000000..e7b996246b --- /dev/null +++ b/azure-pipelines/e2e_assets/test-dll-port-template/vcpkg.json @@ -0,0 +1,4 @@ +{ + "name": "test-dll", + "version": "1.0.0" +} diff --git a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 index dadbad0e60..b8f7a7eae6 100644 --- a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 @@ -1,13 +1,63 @@ . $PSScriptRoot/../end-to-end-tests-prelude.ps1 if (-not $IsWindows) { - return + Write-Host 'Skipping e2e post build checks on non-Windows' + return } -$buildOutput = Run-VcpkgAndCaptureOutput @commonArgs install --overlay-ports="$PSScriptRoot/../e2e_ports" vcpkg-internal-dll-with-no-exports --no-binarycaching -$hasDebugDll = $buildOutput -match "packages/vcpkg-internal-dll-with-no-exports_$Triplet/debug/bin/no_exports\.dll" -$hasReleaseDll = $buildOutput -match "packages/vcpkg-internal-dll-with-no-exports_$Triplet/bin/no_exports\.dll" -$hasSet = $buildOutput -match 'set\(VCPKG_POLICY_DLLS_WITHOUT_EXPORTS enabled\)' -if (-not $hasDebugDll -or -not $hasReleaseDll -or -not $hasSet) { - throw "Did not detect DLLs with no exports." +# DLLs with no exports +Refresh-TestRoot +[string]$buildOutput = Run-VcpkgAndCaptureOutput @commonArgs install --overlay-ports="$PSScriptRoot/../e2e_ports" vcpkg-internal-dll-with-no-exports --no-binarycaching +if (-not $buildOutput.Contains("$packagesRoot\vcpkg-internal-dll-with-no-exports_x86-windows\debug\bin\no_exports.dll") ` + -or -not $buildOutput.Contains("$packagesRoot\vcpkg-internal-dll-with-no-exports_x86-windows\bin\no_exports.dll") ` + -or -not $buildOutput.Contains('set(VCPKG_POLICY_DLLS_WITHOUT_EXPORTS enabled)')) { + throw 'Did not detect DLLs with no exports.' +} + +# DLLs with wrong architecture +Refresh-TestRoot +if (Test-Path "$WorkingRoot/wrong-architecture") { + Remove-Item "$WorkingRoot/wrong-architecture" -Recurse -Force +} + +mkdir "$WorkingRoot/wrong-architecture" +Copy-Item -Recurse "$PSScriptRoot/../e2e_assets/test-dll-port-template" "$WorkingRoot/wrong-architecture/test-dll" +Run-Vcpkg env "$WorkingRoot/wrong-architecture/test-dll/build.cmd" --Triplet x64-windows +Throw-IfFailed + +$buildOutput = Run-VcpkgAndCaptureOutput @commonArgs install --overlay-ports="$WorkingRoot/wrong-architecture" test-dll --no-binarycaching +$expected = "warning: The following files were built for an incorrect architecture:`n" + ` +"warning: $packagesRoot\test-dll_x86-windows\debug\lib\test_dll.lib`n" + ` +" Expected: x86, but was x64`n" + ` +"warning: $packagesRoot\test-dll_x86-windows\lib\test_dll.lib`n" + ` +" Expected: x86, but was x64`n" + ` +"warning: The following files were built for an incorrect architecture:`n" + ` +"warning: $packagesRoot\test-dll_x86-windows\debug\bin\test_dll.dll`n" + ` +" Expected: x86, but was x64`n" + ` +"warning: $packagesRoot\test-dll_x86-windows\bin\test_dll.dll`n" + ` +" Expected: x86, but was x64`n" + +if (-not $buildOutput.Replace("`r`n", "`n").Contains($expected)) { + throw 'Did not detect DLL with wrong architecture.' +} + +# DLLs with no AppContainer bit +Refresh-TestRoot +if (Test-Path "$WorkingRoot/wrong-appcontainer") { + Remove-Item "$WorkingRoot/wrong-appcontainer" -Recurse -Force +} + +mkdir "$WorkingRoot/wrong-appcontainer" +Copy-Item -Recurse "$PSScriptRoot/../e2e_assets/test-dll-port-template" "$WorkingRoot/wrong-appcontainer/test-dll" +Run-Vcpkg env "$WorkingRoot/wrong-appcontainer/test-dll/build.cmd" --Triplet x64-windows +Throw-IfFailed + +$buildOutput = Run-VcpkgAndCaptureOutput --triplet x64-uwp "--x-buildtrees-root=$buildtreesRoot" "--x-install-root=$installRoot" "--x-packages-root=$packagesRoot" install --overlay-ports="$WorkingRoot/wrong-appcontainer" test-dll --no-binarycaching +$expected = "warning: The App Container bit must be set for Windows Store apps. The following DLLs do not have the App Container bit set:`n" + ` +"`n" + ` +" $packagesRoot\test-dll_x64-uwp\debug\bin\test_dll.dll`n" + ` +" $packagesRoot\test-dll_x64-uwp\bin\test_dll.dll`n" + +if (-not $buildOutput.Replace("`r`n", "`n").Contains($expected)) { + throw 'Did not detect DLL with wrong appcontainer.' } diff --git a/src/vcpkg/base/files.cpp b/src/vcpkg/base/files.cpp index 71f1f40efe..d075ba63fb 100644 --- a/src/vcpkg/base/files.cpp +++ b/src/vcpkg/base/files.cpp @@ -3543,13 +3543,17 @@ namespace vcpkg void print_paths(const std::vector& paths) { - std::string message = "\n"; + LocalizedString ls; + ls.append_raw('\n'); for (const Path& p : paths) { - Strings::append(message, " ", p.generic_u8string(), '\n'); + auto as_preferred = p; + as_preferred.make_preferred(); + ls.append_indent().append_raw(as_preferred).append_raw('\n'); } - message.push_back('\n'); - msg::write_unlocalized_text_to_stdout(Color::none, message); + + ls.append_raw('\n'); + msg::print(ls); } IExclusiveFileLock::~IExclusiveFileLock() = default; diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index 096091dc95..febfcd1e2d 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -484,7 +484,6 @@ namespace vcpkg::PostBuildLint { msg::println_warning(msgPortBugDllAppContainerBitNotSet); print_paths(dlls_with_improper_uwp_bit); - msg::println_warning(msgPortBugDllAppContainerBitNotSet); return LintStatus::PROBLEM_DETECTED; } @@ -1025,7 +1024,9 @@ namespace vcpkg::PostBuildLint 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); + } if (!build_info.policies.is_enabled(BuildPolicy::SKIP_ARCHITECTURE_CHECK)) { @@ -1077,7 +1078,10 @@ namespace vcpkg::PostBuildLint error_count += check_exports_of_dlls(build_info.policies, dlls); error_count += check_uwp_bit_of_dlls(pre_build_info.cmake_system_name, dlls); error_count += check_outdated_crt_linkage_of_dlls(dlls, build_info, pre_build_info); - error_count += check_dll_architecture(pre_build_info.target_architecture, dlls); + if (!build_info.policies.is_enabled(BuildPolicy::SKIP_ARCHITECTURE_CHECK)) + { + error_count += check_dll_architecture(pre_build_info.target_architecture, dlls); + } } break; case LinkageType::STATIC: From 09ecdfbf6711663487cd333bb10617642d71230b Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 14 Dec 2022 17:12:10 -0600 Subject: [PATCH 04/33] Add static lib with wrong CRT linkage test. --- .../test-dll-port-template/build.cmd | 4 ++-- .../build.cmd | 6 +++++ .../portfile.cmake | 10 ++++++++ .../test-lib-port-template-dynamic-crt/test.c | 6 +++++ .../test-lib-port-template-dynamic-crt/test.h | 1 + .../vcpkg.json | 4 ++++ .../post-build-checks.ps1 | 24 +++++++++++++++++++ 7 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/build.cmd create mode 100644 azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/portfile.cmake create mode 100644 azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.c create mode 100644 azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.h create mode 100644 azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/vcpkg.json diff --git a/azure-pipelines/e2e_assets/test-dll-port-template/build.cmd b/azure-pipelines/e2e_assets/test-dll-port-template/build.cmd index 4f4b194703..2f45d976d0 100644 --- a/azure-pipelines/e2e_assets/test-dll-port-template/build.cmd +++ b/azure-pipelines/e2e_assets/test-dll-port-template/build.cmd @@ -1,4 +1,4 @@ mkdir "%~dp0debug" mkdir "%~dp0release" -cl /EHsc /MDd "%~dp0test.c" "%~dp0test.def" /Fe"%~dp0debug\test_dll.dll" /link /DLL -cl /EHsc /MD "%~dp0test.c" "%~dp0test.def" /Fe"%~dp0release\test_dll.dll" /link /DLL +cl /MDd "%~dp0test.c" "%~dp0test.def" /Fo"%~dp0debug\test.obj" /Fe"%~dp0debug\test_dll.dll" /link /DLL +cl /MD "%~dp0test.c" "%~dp0test.def" /Fo"%~dp0release\test.obj" /Fe"%~dp0release\test_dll.dll" /link /DLL diff --git a/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/build.cmd b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/build.cmd new file mode 100644 index 0000000000..e1a39e9128 --- /dev/null +++ b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/build.cmd @@ -0,0 +1,6 @@ +mkdir "%~dp0debug" +mkdir "%~dp0release" +cl /c /MDd "%~dp0test.c" /Fo"%~dp0debug\test.obj" +lib "%~dp0debug\test.obj" /OUT:"%~dp0debug\test_lib.lib" +cl /c /MD "%~dp0test.c" /Fo"%~dp0release\test.obj" +lib "%~dp0release\test.obj" /OUT:"%~dp0release\test_lib.lib" diff --git a/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/portfile.cmake b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/portfile.cmake new file mode 100644 index 0000000000..7b9a9e06a6 --- /dev/null +++ b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/portfile.cmake @@ -0,0 +1,10 @@ +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/lib") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug/lib") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/include") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share/${PORT}") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/debug/test_lib.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/debug/lib") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/release/test_lib.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/lib") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/test.h" DESTINATION "${CURRENT_PACKAGES_DIR}/include") +file(TOUCH "${CURRENT_PACKAGES_DIR}/share/${PORT}/copyright") diff --git a/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.c b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.c new file mode 100644 index 0000000000..608e24b4cd --- /dev/null +++ b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.c @@ -0,0 +1,6 @@ +#include + +int __cdecl use_me() { + puts("You called the static lib function!"); + return 42; +} diff --git a/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.h b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.h new file mode 100644 index 0000000000..10d2052384 --- /dev/null +++ b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.h @@ -0,0 +1 @@ + // empty test header diff --git a/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/vcpkg.json b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/vcpkg.json new file mode 100644 index 0000000000..aace75bf6b --- /dev/null +++ b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/vcpkg.json @@ -0,0 +1,4 @@ +{ + "name": "test-lib", + "version": "1.0.0" +} diff --git a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 index b8f7a7eae6..bb105c9ffd 100644 --- a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 @@ -61,3 +61,27 @@ $expected = "warning: The App Container bit must be set for Windows Store apps. if (-not $buildOutput.Replace("`r`n", "`n").Contains($expected)) { throw 'Did not detect DLL with wrong appcontainer.' } + +# Wrong CRT linkage +Refresh-TestRoot +if (Test-Path "$WorkingRoot/wrong-crt") { + Remove-Item "$WorkingRoot/wrong-crt" -Recurse -Force +} + +mkdir "$WorkingRoot/wrong-crt" +Copy-Item -Recurse "$PSScriptRoot/../e2e_assets/test-lib-port-template-dynamic-crt" "$WorkingRoot/wrong-crt/test-lib" +Run-Vcpkg env "$WorkingRoot/wrong-crt/test-lib/build.cmd" --Triplet x86-windows-static +Throw-IfFailed + +$buildOutput = Run-VcpkgAndCaptureOutput --triplet x86-windows-static "--x-buildtrees-root=$buildtreesRoot" "--x-install-root=$installRoot" "--x-packages-root=$packagesRoot" install --overlay-ports="$WorkingRoot/wrong-crt" test-lib --no-binarycaching +$expected = "warning: Invalid crt linkage. Expected Debug,Static, but the following libs had:`n" + ` +" $packagesRoot\test-lib_x86-windows-static\debug\lib\test_lib.lib: Debug,Dynamic`n" + ` +"warning: To inspect the lib files, use:`n" + ` +" dumpbin.exe /directives mylibfile.lib`n" + ` +"warning: Invalid crt linkage. Expected Release,Static, but the following libs had:`n" + ` +" $packagesRoot\test-lib_x86-windows-static\lib\test_lib.lib: Release,Dynamic`n" + ` +"warning: To inspect the lib files, use:`n" + ` +" dumpbin.exe /directives mylibfile.lib`n" +if (-not $buildOutput.Replace("`r`n", "`n").Contains($expected)) { + throw 'Did not detect lib with wrong CRT linkage.' +} From 97f7f98aecae0c7920356d18dae825fd7b2b47d4 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 14 Dec 2022 18:58:03 -0600 Subject: [PATCH 05/33] WIP directives --- .../post-build-checks.ps1 | 2 +- include/vcpkg/base/cofffilereader.h | 69 +++++++++++- include/vcpkg/postbuildlint.buildtype.h | 29 ----- src/vcpkg/base/cofffilereader.cpp | 97 +++++++++++----- src/vcpkg/postbuildlint.buildtype.cpp | 63 ----------- src/vcpkg/postbuildlint.cpp | 105 +++++++++--------- 6 files changed, 191 insertions(+), 174 deletions(-) delete mode 100644 include/vcpkg/postbuildlint.buildtype.h delete mode 100644 src/vcpkg/postbuildlint.buildtype.cpp diff --git a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 index bb105c9ffd..a5325dfbd5 100644 --- a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 @@ -73,7 +73,7 @@ Copy-Item -Recurse "$PSScriptRoot/../e2e_assets/test-lib-port-template-dynamic-c Run-Vcpkg env "$WorkingRoot/wrong-crt/test-lib/build.cmd" --Triplet x86-windows-static Throw-IfFailed -$buildOutput = Run-VcpkgAndCaptureOutput --triplet x86-windows-static "--x-buildtrees-root=$buildtreesRoot" "--x-install-root=$installRoot" "--x-packages-root=$packagesRoot" install --overlay-ports="$WorkingRoot/wrong-crt" test-lib --no-binarycaching +$buildOutput = Run-VcpkgAndCaptureOutput --triplet x86-windows-static "--x-buildtrees-root=$buildtreesRoot" "--x-install-root=$installRoot" "--x-packages-root=$packagesRoot" install --overlay-ports="$WorkingRoot/wrong-crt" test-lib --no-binarycaching --debug $expected = "warning: Invalid crt linkage. Expected Debug,Static, but the following libs had:`n" + ` " $packagesRoot\test-lib_x86-windows-static\debug\lib\test_lib.lib: Debug,Dynamic`n" + ` "warning: To inspect the lib files, use:`n" + ` diff --git a/include/vcpkg/base/cofffilereader.h b/include/vcpkg/base/cofffilereader.h index d175c60fa9..50554c2351 100644 --- a/include/vcpkg/base/cofffilereader.h +++ b/include/vcpkg/base/cofffilereader.h @@ -114,6 +114,50 @@ namespace vcpkg uint32_t size; }; + enum class SectionTableFlags : uint32_t + { + TypeNoPad = 0x00000008u, + CntCode = 0x00000020u, + CntInitializedData = 0x00000040u, + CntUniniitalizedData = 0x00000080u, + LinkOther = 0x00000100u, + LinkInfo = 0x00000200u, + LinkRemove = 0x00000400u, + LinkComdat = 0x00001000u, + GpRel = 0x00008000u, + MemPurgable = 0x00020000u, + // Mem16Bit has the same constant as MemPurgable?! + MemLocked = 0x00040000u, + MemPreload = 0x00080000u, + Align1Bytes = 0x00100000u, + Align2Bytes = 0x00200000u, + Align4Bytes = 0x00300000u, + Align8Bytes = 0x00400000u, + Align16Bytes = 0x00500000u, + Align32Bytes = 0x00600000u, + Align64Bytes = 0x00700000u, + Align128Bytes = 0x00800000u, + Align256Bytes = 0x00900000u, + Align512Bytes = 0x00A00000u, + Align1024Bytes = 0x00B00000u, + Align2048Bytes = 0x00C00000u, + Align4096Bytes = 0x00D00000u, + Align8192Bytes = 0x00E00000u, + LinkNumberOfRelocationsOverflow = 0x01000000u, + MemDiscardable = 0x02000000u, + MemNotCached = 0x04000000u, + MemNotPaged = 0x08000000u, + MemShared = 0x10000000u, + MemExecute = 0x20000000u, + MemRead = 0x40000000u, + MemWrite = 0x80000000u + }; + + constexpr bool operator&(SectionTableFlags lhs, SectionTableFlags rhs) noexcept + { + return (static_cast(lhs) & static_cast(rhs)) != 0; + } + struct SectionTableHeader { unsigned char name[8]; @@ -125,7 +169,7 @@ namespace vcpkg uint32_t pointer_to_line_numbers; uint16_t number_of_relocations; uint16_t number_of_line_numbers; - uint32_t characteristics; + SectionTableFlags characteristics; }; struct ExportDirectoryTable @@ -318,8 +362,29 @@ namespace vcpkg uint64_t decoded_size() const; }; + struct ImportHeader + { + uint16_t sig1; // must be IMAGE_FILE_MACHINE_UNKNOWN + uint16_t sig2; // must be 0xFFFF + uint16_t version; + uint16_t machine; + uint32_t date_time_stamp; + uint32_t size_of_data; + uint16_t ordinal_hint; + uint16_t type_and_name_type; + // 2 bits: type + // 3 bits: name type + // 11 bits: reserved and must be 0 + }; + + struct LibInformation + { + std::vector machine_types; + std::vector linker_directives; + }; + ExpectedL try_read_dll_metadata(ReadFilePointer& f); ExpectedL try_read_if_dll_has_exports(const DllMetadata& dll, ReadFilePointer& f); ExpectedL> try_read_dll_imported_dll_names(const DllMetadata& dll, ReadFilePointer& f); - std::vector read_lib_machine_types(const ReadFilePointer& f); + LibInformation read_lib_information(const ReadFilePointer& f); } diff --git a/include/vcpkg/postbuildlint.buildtype.h b/include/vcpkg/postbuildlint.buildtype.h deleted file mode 100644 index 8404305590..0000000000 --- a/include/vcpkg/postbuildlint.buildtype.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include - -#include - -namespace vcpkg::PostBuildLint -{ - struct BuildType - { - BuildType() = delete; - - constexpr BuildType(ConfigurationType c, LinkageType l) : config(c), linkage(l) { } - - bool has_crt_linker_option(StringView sv) const; - StringLiteral to_string() const; - - ConfigurationType config; - LinkageType linkage; - - friend bool operator==(const BuildType& lhs, const BuildType& rhs) - { - return lhs.config == rhs.config && lhs.linkage == rhs.linkage; - } - friend bool operator!=(const BuildType& lhs, const BuildType& rhs) { return !(lhs == rhs); } - }; -} diff --git a/src/vcpkg/base/cofffilereader.cpp b/src/vcpkg/base/cofffilereader.cpp index 309b0987fa..1dcf3c1054 100644 --- a/src/vcpkg/base/cofffilereader.cpp +++ b/src/vcpkg/base/cofffilereader.cpp @@ -255,25 +255,6 @@ namespace static_assert(sizeof(ArchiveMemberHeader) == 60, "The ArchiveMemberHeader struct must match its on-disk representation"); - MachineType read_import_machine_type_after_sig1(const ReadFilePointer& f) - { - struct ImportHeaderPrefixAfterSig1 - { - uint16_t sig2; - uint16_t version; - uint16_t machine; - } tmp; - - Checks::check_exit(VCPKG_LINE_INFO, f.read(&tmp, sizeof(tmp), 1) == 1); - if (tmp.sig2 == 0xFFFF) - { - return to_machine_type(tmp.machine); - } - - // This can happen, for example, if this is a .drectve member - return MachineType::UNKNOWN; - } - void read_and_verify_archive_file_signature(const ReadFilePointer& f) { static constexpr StringLiteral FILE_START = "!\n"; @@ -345,22 +326,80 @@ namespace return offsets; } - std::vector read_machine_types_from_archive_members(const vcpkg::ReadFilePointer& f, + LibInformation read_machine_types_from_archive_members(const vcpkg::ReadFilePointer& f, const std::vector& member_offsets) { - std::vector machine_types; // used as a set because n is tiny + std::vector machine_types; // used as sets because n is tiny + std::vector directives; // Next we have the obj and pseudo-object files for (unsigned int offset : member_offsets) { // Skip the header, no need to read it - Checks::check_exit(VCPKG_LINE_INFO, f.seek(offset + sizeof(ArchiveMemberHeader), SEEK_SET) == 0); - uint16_t machine_type_raw; - Checks::check_exit(VCPKG_LINE_INFO, f.read(&machine_type_raw, sizeof(machine_type_raw), 1) == 1); - - auto result_machine_type = to_machine_type(machine_type_raw); + const auto coff_base = offset + sizeof(ArchiveMemberHeader); + Checks::check_exit(VCPKG_LINE_INFO, f.seek(coff_base, SEEK_SET) == 0); + static_assert(sizeof(CoffFileHeader) == sizeof(ImportHeader), "Boom"); + char loaded_header[sizeof(CoffFileHeader)]; + Checks::check_exit(VCPKG_LINE_INFO, f.read(&loaded_header, sizeof(loaded_header), 1) == 1); + + CoffFileHeader coff_header; + ::memcpy(&coff_header, loaded_header, sizeof(coff_header)); + auto result_machine_type = to_machine_type(coff_header.machine); + bool import_object = false; if (result_machine_type == MachineType::UNKNOWN) { - result_machine_type = read_import_machine_type_after_sig1(f); + ImportHeader import_header; + ::memcpy(&import_header, loaded_header, sizeof(import_header)); + if (import_header.sig2 == 0xFFFFu) + { + import_object = true; + result_machine_type = to_machine_type(import_header.machine); + } + } + + if (!import_object) + { + // Object files shouldn't have optional headers, but the spec says we should skip over one if any + f.seek(coff_header.size_of_optional_header, SEEK_CUR); + // Read section headers + std::vector sections; + sections.resize(coff_header.number_of_sections); + Checks::check_exit(VCPKG_LINE_INFO, + f.read(sections.data(), + sizeof(SectionTableHeader), + coff_header.number_of_sections) == coff_header.number_of_sections); + // Look for linker directive sections + for (auto&& section : sections) + { + if (!(section.characteristics & SectionTableFlags::LinkInfo) + || memcmp(".drectve", §ion.name, 8) != 0 + || section.number_of_relocations != 0 + || section.number_of_line_numbers != 0) + { + continue; + } + + // read the actual directive + std::string directive; + const auto section_offset = coff_base + section.pointer_to_raw_data; + Checks::check_exit(VCPKG_LINE_INFO, f.seek(section_offset, SEEK_SET) == 0); + directive.resize(section.size_of_raw_data); + auto fun = f.read(directive.data(), 1, section.size_of_raw_data); + Checks::check_exit(VCPKG_LINE_INFO, + fun == + section.size_of_raw_data); + + if (Strings::starts_with(directive, StringLiteral{"\xEF\xBB\xBF"})) + { + // chop of the BOM + directive.erase(0, 3); + } + + auto insertion_point = std::lower_bound(directives.begin(), directives.end(), directive); + if (insertion_point == directives.end() || *insertion_point != directive) + { + directives.insert(insertion_point, std::move(directive)); + } + } } if (result_machine_type == MachineType::UNKNOWN || @@ -373,7 +412,7 @@ namespace } std::sort(machine_types.begin(), machine_types.end()); - return machine_types; + return LibInformation{std::move(machine_types), std::move(directives)}; } } // unnamed namespace @@ -556,7 +595,7 @@ namespace vcpkg }); } - std::vector read_lib_machine_types(const ReadFilePointer& f) + LibInformation read_lib_information(const ReadFilePointer& f) { read_and_verify_archive_file_signature(f); read_and_skip_first_linker_member(f); diff --git a/src/vcpkg/postbuildlint.buildtype.cpp b/src/vcpkg/postbuildlint.buildtype.cpp deleted file mode 100644 index c4507e69d3..0000000000 --- a/src/vcpkg/postbuildlint.buildtype.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include - -#include - -namespace vcpkg::PostBuildLint -{ - bool BuildType::has_crt_linker_option(StringView sv) const - { - // "/DEFAULTLIB:LIBCMTD"; - // "/DEFAULTLIB:MSVCRTD"; - // "/DEFAULTLIB:LIBCMT[^D]"; - // "/DEFAULTLIB:LIBCMT[^D]"; - - constexpr static const StringLiteral static_crt = "/DEFAULTLIB:LIBCMT"; - constexpr static const StringLiteral dynamic_crt = "/DEFAULTLIB:MSVCRT"; - - StringView option = linkage == LinkageType::STATIC ? static_crt : dynamic_crt; - - auto found = Strings::case_insensitive_ascii_search(sv, option); - if (found == sv.end()) - { - return false; - } - - auto option_end = found + option.size(); - if (config == ConfigurationType::DEBUG) - { - if (option_end == sv.end() || !Strings::icase_eq(*option_end, 'd')) - { - return false; - } - ++option_end; - } - - return option_end == sv.end() || ParserBase::is_whitespace(*option_end); - } - - StringLiteral BuildType::to_string() const - { - if (config == ConfigurationType::DEBUG) - { - if (linkage == LinkageType::STATIC) - { - return "Debug,Static"; - } - else - { - return "Debug,Dynamic"; - } - } - else - { - if (linkage == LinkageType::STATIC) - { - return "Release,Static"; - } - else - { - return "Release,Dynamic"; - } - } - } -} diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index febfcd1e2d..05d90230d7 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -1,12 +1,12 @@ #include #include +#include #include #include #include #include #include -#include #include #include @@ -570,8 +570,9 @@ namespace vcpkg::PostBuildLint msg::extension = ".lib", msg::path = file); - const auto machine_types = Util::fmap(read_lib_machine_types(fs.open_for_read(file, VCPKG_LINE_INFO)), - [](MachineType mt) { return get_actual_architecture(mt); }); + const auto machine_types = + Util::fmap(read_lib_information(fs.open_for_read(file, VCPKG_LINE_INFO)).machine_types, + [](MachineType mt) { return get_actual_architecture(mt); }); // Either machine_types is empty (meaning this lib is architecture independent), or // we need at least one of the machine types to match. // Agnostic example: Folly's debug library @@ -848,61 +849,68 @@ namespace vcpkg::PostBuildLint struct BuildTypeAndFile { Path file; - BuildType build_type; + bool has_static_release = false; + bool has_static_debug = false; + bool has_dynamic_release = false; + bool has_dynamic_debug = false; }; - static LintStatus check_crt_linkage_of_libs(const BuildType& expected_build_type, - const std::vector& libs, - const Path& dumpbin_exe) + static LintStatus check_crt_linkage_of_libs(const Filesystem& fs, + const BuildInfo& build_info, + bool expect_release, + const std::vector& libs) { - auto bad_build_types = std::vector({ - {ConfigurationType::DEBUG, LinkageType::STATIC}, - {ConfigurationType::DEBUG, LinkageType::DYNAMIC}, - {ConfigurationType::RELEASE, LinkageType::STATIC}, - {ConfigurationType::RELEASE, LinkageType::DYNAMIC}, - }); - Util::erase_remove(bad_build_types, expected_build_type); - + (void)build_info; + (void)expect_release; std::vector libs_with_invalid_crt; - for (const Path& lib : libs) { - auto cmd_line = Command(dumpbin_exe).string_arg("/directives").string_arg(lib); - const auto maybe_output = flatten_out(cmd_execute_and_capture_output(cmd_line), "dumpbin"); - if (const auto output = maybe_output.get()) + auto lib_file = fs.try_open_for_read(lib).value_or_exit(VCPKG_LINE_INFO); + auto lib_info = read_lib_information(lib_file); + Debug::println("The lib " + lib.native() + + " has directives: " + Strings::join(" ", lib_info.linker_directives)); + + BuildTypeAndFile this_lib{lib}; + constexpr static const StringLiteral static_release_crt = "/DEFAULTLIB:\"LIBCMT\""; + constexpr static const StringLiteral static_debug_crt = "/DEFAULTLIB:\"LIBCMTd\""; + constexpr static const StringLiteral dynamic_release_crt = "/DEFAULTLIB:\"MSVCRT\""; + constexpr static const StringLiteral dynamic_debug_crt = "/DEFAULTLIB:\"MSVCRTd\""; + + for (auto&& directive : lib_info.linker_directives) { - for (const BuildType& bad_build_type : bad_build_types) + if (Strings::case_insensitive_ascii_equals(directive, static_release_crt)) { - if (bad_build_type.has_crt_linker_option(*output)) - { - libs_with_invalid_crt.push_back({lib, bad_build_type}); - break; - } + this_lib.has_static_release = true; + } + else if (Strings::case_insensitive_ascii_equals(directive, static_debug_crt)) + { + this_lib.has_static_debug = true; + } + else if (Strings::case_insensitive_ascii_equals(directive, dynamic_release_crt)) + { + this_lib.has_dynamic_release = true; + } + else if (Strings::case_insensitive_ascii_equals(directive, dynamic_debug_crt)) + { + this_lib.has_dynamic_debug = true; } - } - else - { - Checks::msg_exit_with_message(VCPKG_LINE_INFO, - msg::format(msgCommandFailed, msg::command_line = cmd_line.command_line()) - .append_raw('\n') - .append_raw(maybe_output.error())); } } - if (!libs_with_invalid_crt.empty()) - { - msg::println_warning(msgPortBugInvalidCrtLinkage, msg::expected = expected_build_type.to_string()); + // if (!libs_with_invalid_crt.empty()) + //{ + // msg::println_warning(msgPortBugInvalidCrtLinkage, msg::expected = expected_build_type.to_string()); - for (const BuildTypeAndFile& btf : libs_with_invalid_crt) - { - msg::write_unlocalized_text_to_stdout( - Color::warning, fmt::format(" {}: {}\n", btf.file, btf.build_type.to_string())); - } + // for (const BuildTypeAndFile& btf : libs_with_invalid_crt) + // { + // msg::write_unlocalized_text_to_stdout( + // Color::warning, fmt::format(" {}: {}\n", btf.file, btf.build_type.to_string())); + // } - msg::println_warning(msg::format(msgPortBugInspectFiles, msg::extension = "lib") - .append_raw("\n dumpbin.exe /directives mylibfile.lib")); - return LintStatus::PROBLEM_DETECTED; - } + // msg::println_warning(msg::format(msgPortBugInspectFiles, msg::extension = "lib") + // .append_raw("\n dumpbin.exe /directives mylibfile.lib")); + // return LintStatus::PROBLEM_DETECTED; + //} return LintStatus::SUCCESS; } @@ -977,8 +985,6 @@ namespace vcpkg::PostBuildLint const BuildInfo& build_info) { const auto& fs = paths.get_filesystem(); - - // for dumpbin const Toolset& toolset = paths.get_toolset(pre_build_info); const auto package_dir = paths.package_dir(spec); @@ -1096,11 +1102,10 @@ namespace vcpkg::PostBuildLint { if (!build_info.policies.is_enabled(BuildPolicy::ONLY_RELEASE_CRT)) { - error_count += check_crt_linkage_of_libs( - BuildType(ConfigurationType::DEBUG, build_info.crt_linkage), debug_libs, toolset.dumpbin); + error_count += check_crt_linkage_of_libs(fs, build_info, false, debug_libs); } - error_count += check_crt_linkage_of_libs( - BuildType(ConfigurationType::RELEASE, build_info.crt_linkage), release_libs, toolset.dumpbin); + + error_count += check_crt_linkage_of_libs(fs, build_info, true, release_libs); } break; } From dd33985b85e106095d79bb287bcabc0f52bb3dcd Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 15 Dec 2022 04:26:21 -0500 Subject: [PATCH 06/33] Finish the directives ripout. --- include/vcpkg/base/cofffilereader.h | 1 + include/vcpkg/base/messages.h | 29 +++++- include/vcpkg/postbuildlint.h | 16 ++- locales/messages.json | 10 +- src/vcpkg-test/coffilereader.cpp | 36 +++++++ src/vcpkg/base/cofffilereader.cpp | 120 +++++++++++++++++++---- src/vcpkg/base/messages.cpp | 5 + src/vcpkg/build.cpp | 2 +- src/vcpkg/postbuildlint.cpp | 146 +++++++++++++++++++++++----- 9 files changed, 307 insertions(+), 58 deletions(-) create mode 100644 src/vcpkg-test/coffilereader.cpp diff --git a/include/vcpkg/base/cofffilereader.h b/include/vcpkg/base/cofffilereader.h index 50554c2351..31b0862df1 100644 --- a/include/vcpkg/base/cofffilereader.h +++ b/include/vcpkg/base/cofffilereader.h @@ -383,6 +383,7 @@ namespace vcpkg std::vector linker_directives; }; + std::vector tokenize_command_line(StringView cmd_line); ExpectedL try_read_dll_metadata(ReadFilePointer& f); ExpectedL try_read_if_dll_has_exports(const DllMetadata& dll, ReadFilePointer& f); ExpectedL> try_read_dll_imported_dll_names(const DllMetadata& dll, ReadFilePointer& f); diff --git a/include/vcpkg/base/messages.h b/include/vcpkg/base/messages.h index 5da1462517..762f77cf5e 100644 --- a/include/vcpkg/base/messages.h +++ b/include/vcpkg/base/messages.h @@ -1811,6 +1811,10 @@ namespace vcpkg (msg::value), "Example of {value} is 'unknownlicense'", "Unknown license identifier '{value}'. Known values are listed at https://spdx.org/licenses/"); + DECLARE_MESSAGE(LinkageDynamicDebug, (), "", "Dynamic Debug"); + DECLARE_MESSAGE(LinkageDynamicRelease, (), "", "Dynamic Release"); + DECLARE_MESSAGE(LinkageStaticDebug, (), "", "Static Debug"); + DECLARE_MESSAGE(LinkageStaticRelease, (), "", "Static Release"); DECLARE_MESSAGE(ListOfValidFieldsForControlFiles, (), "", @@ -2084,10 +2088,27 @@ namespace vcpkg "The folder /include exists in a cmake helper port; this is incorrect, since only cmake " "files should be installed"); DECLARE_MESSAGE(PortBugInspectFiles, (msg::extension), "", "To inspect the {extension} files, use:"); - DECLARE_MESSAGE(PortBugInvalidCrtLinkage, - (msg::expected), - "{expected} is the expected build type", - "Invalid crt linkage. Expected {expected}, but the following libs had:"); + DECLARE_MESSAGE( + PortBugInvalidCrtLinkage, + (msg::expected), + "{expected} is one of LinkageDynamicDebug/LinkageDynamicRelease/LinkageStaticDebug/LinkageStaticRelease. " + "Immediately after this message is a file by file list with what linkages they contain. 'CRT' is an acronym " + "meaning C Runtime. FIXME add link to /MT/MTd/MD/MDd switch docs here. This is complicated because a binary " + "can link with more than one CRT.\n" + "Example fully formatted message:\n" + "The following binaries should use the Dynamic Debug CRT.\n" + " C:\\some\\path\\to\\sane\\lib links with: Dynamic Release\n" + " C:\\some\\path\\to\\lib links with:\n" + " Static Debug\n" + " Dynamic Release\n" + " C:\\some\\different\\path\\to\\a\\dll links with:\n" + " Static Debug\n" + " Dynamic Debug\n", + "The following binaries should use the {expected} CRT."); + DECLARE_MESSAGE(PortBugInvalidCrtLinkageEntry, + (msg::path), + "See explanation in PortBugInvalidCrtLinkage", + "{path} links with:"); DECLARE_MESSAGE(PortBugMergeLibCMakeDir, (msg::spec), "", diff --git a/include/vcpkg/postbuildlint.h b/include/vcpkg/postbuildlint.h index aadec0f3a1..b1b4b4b707 100644 --- a/include/vcpkg/postbuildlint.h +++ b/include/vcpkg/postbuildlint.h @@ -1,20 +1,16 @@ #pragma once #include +#include #include #include namespace vcpkg { - struct PackageSpec; -} - -namespace vcpkg::PostBuildLint -{ - size_t perform_all_checks(const PackageSpec& spec, - const VcpkgPaths& paths, - const PreBuildInfo& pre_build_info, - const BuildInfo& build_info, - const Path& port_dir); + size_t perform_post_build_lint_checks(const PackageSpec& spec, + const VcpkgPaths& paths, + const PreBuildInfo& pre_build_info, + const BuildInfo& build_info, + const Path& port_dir); } diff --git a/locales/messages.json b/locales/messages.json index c2ee499868..d0add3cf95 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -781,6 +781,10 @@ "_LicenseExpressionUnknownException.comment": "Example of {value} is 'unknownexception'", "LicenseExpressionUnknownLicense": "Unknown license identifier '{value}'. Known values are listed at https://spdx.org/licenses/", "_LicenseExpressionUnknownLicense.comment": "Example of {value} is 'unknownlicense'", + "LinkageDynamicDebug": "Dynamic Debug", + "LinkageDynamicRelease": "Dynamic Release", + "LinkageStaticDebug": "Static Debug", + "LinkageStaticRelease": "Static Release", "ListOfValidFieldsForControlFiles": "This is the list of valid fields for CONTROL files (case-sensitive):", "LoadingCommunityTriplet": "-- [COMMUNITY] Loading triplet configuration from: {path}", "_LoadingCommunityTriplet.comment": "'-- [COMMUNITY]' at the beginning must be preserved An example of {path} is /foo/bar.", @@ -925,8 +929,10 @@ "PortBugIncludeDirInCMakeHelperPort": "The folder /include exists in a cmake helper port; this is incorrect, since only cmake files should be installed", "PortBugInspectFiles": "To inspect the {extension} files, use:", "_PortBugInspectFiles.comment": "An example of {extension} is .exe.", - "PortBugInvalidCrtLinkage": "Invalid crt linkage. Expected {expected}, but the following libs had:", - "_PortBugInvalidCrtLinkage.comment": "{expected} is the expected build type", + "PortBugInvalidCrtLinkage": "The following binaries should use the {expected} CRT.", + "_PortBugInvalidCrtLinkage.comment": "{expected} is one of LinkageDynamicDebug/LinkageDynamicRelease/LinkageStaticDebug/LinkageStaticRelease. Immediately after this message is a file by file list with what linkages they contain. 'CRT' is an acronym meaning C Runtime. FIXME add link to /MT/MTd/MD/MDd switch docs here. This is complicated because a binary can link with more than one CRT.\nExample fully formatted message:\nThe following binaries should use the Dynamic Debug CRT.\n C:\\some\\path\\to\\sane\\lib links with: Dynamic Release\n C:\\some\\path\\to\\lib links with:\n Static Debug\n Dynamic Release\n C:\\some\\different\\path\\to\\a\\dll links with:\n Static Debug\n Dynamic Debug\n", + "PortBugInvalidCrtLinkageEntry": "{path} links with:", + "_PortBugInvalidCrtLinkageEntry.comment": "See explanation in PortBugInvalidCrtLinkage An example of {path} is /foo/bar.", "PortBugMergeLibCMakeDir": "The /lib/cmake folder should be merged with /debug/lib/cmake and moved to /share/{spec}/cmake. Please use the helper function `vcpkg_cmake_config_fixup()` from the port vcpkg-cmake-config.`", "_PortBugMergeLibCMakeDir.comment": "An example of {spec} is zlib:x64-windows.", "PortBugMismatchedNumberOfBinaries": "Mismatching number of debug and release binaries.", diff --git a/src/vcpkg-test/coffilereader.cpp b/src/vcpkg-test/coffilereader.cpp new file mode 100644 index 0000000000..4dfda982ad --- /dev/null +++ b/src/vcpkg-test/coffilereader.cpp @@ -0,0 +1,36 @@ +#include + +#include + +using namespace vcpkg; + +TEST_CASE ("tokenize-command-line", "[cofffilereader]") +{ + using Vec = std::vector; + CHECK(tokenize_command_line("") == Vec{}); + CHECK(tokenize_command_line("a b c") == Vec{"a", "b", "c"}); + CHECK(tokenize_command_line("a b c ") == Vec{"a", "b", "c"}); + CHECK(tokenize_command_line(" a b c ") == Vec{"a", "b", "c"}); + CHECK(tokenize_command_line(" a b c") == Vec{"a", "b", "c"}); + CHECK(tokenize_command_line("a\"embedded quotes\"") == Vec{"aembedded quotes"}); + CHECK(tokenize_command_line("a\\slash\\b") == Vec{"a\\slash\\b"}); + // n backslashes not followed by a quotation mark produce n backslashes + CHECK(tokenize_command_line("a\\\\\\slash\\b") == Vec{"a\\\\\\slash\\b"}); + CHECK(tokenize_command_line("an arg with \\\"quotes") == Vec{"an", "arg", "with", "\"quotes"}); + CHECK(tokenize_command_line("an arg with \"\\\"quotes\"") == Vec{"an", "arg", "with", "\"quotes"}); + CHECK(tokenize_command_line("arg \"quoted\" suffix") == Vec{"arg", "quoted", "suffix"}); + // 2n + 1 backslashes followed by a quotation mark produce n backslashes followed by a (escaped) quotation mark + CHECK(tokenize_command_line("arg \"quoted\\\" suffix") == Vec{"arg", "quoted\" suffix"}); + // 2n backslashes followed by a quotation mark produce n backslashes followed by a (terminal) quotation mark + CHECK(tokenize_command_line("arg \"quoted\\\\\" suffix") == Vec{"arg", "quoted\\", "suffix"}); + CHECK(tokenize_command_line("arg \"quoted\\\\\\\" suffix") == Vec{"arg", "quoted\\\" suffix"}); + CHECK(tokenize_command_line("arg \"quoted\\\\\\\\\" suffix") == Vec{"arg", "quoted\\\\", "suffix"}); + // The above cases but at the end + CHECK(tokenize_command_line("\\") == Vec{"\\"}); + CHECK(tokenize_command_line("\\\\") == Vec{"\\\\"}); + CHECK(tokenize_command_line("\\\\\\") == Vec{"\\\\\\"}); + CHECK(tokenize_command_line("arg \"quoted\\\"") == Vec{"arg", "quoted\""}); + CHECK(tokenize_command_line("arg \"quoted\\\\\"") == Vec{"arg", "quoted\\"}); + CHECK(tokenize_command_line("arg \"quoted\\\\\\\"") == Vec{"arg", "quoted\\\""}); + CHECK(tokenize_command_line("arg \"quoted\\\\\\\\\"") == Vec{"arg", "quoted\\\\"}); +} diff --git a/src/vcpkg/base/cofffilereader.cpp b/src/vcpkg/base/cofffilereader.cpp index 1dcf3c1054..eff5c9f229 100644 --- a/src/vcpkg/base/cofffilereader.cpp +++ b/src/vcpkg/base/cofffilereader.cpp @@ -326,8 +326,8 @@ namespace return offsets; } - LibInformation read_machine_types_from_archive_members(const vcpkg::ReadFilePointer& f, - const std::vector& member_offsets) + LibInformation read_lib_information_from_archive_members(const vcpkg::ReadFilePointer& f, + const std::vector& member_offsets) { std::vector machine_types; // used as sets because n is tiny std::vector directives; @@ -370,34 +370,35 @@ namespace // Look for linker directive sections for (auto&& section : sections) { - if (!(section.characteristics & SectionTableFlags::LinkInfo) - || memcmp(".drectve", §ion.name, 8) != 0 - || section.number_of_relocations != 0 - || section.number_of_line_numbers != 0) + if (!(section.characteristics & SectionTableFlags::LinkInfo) || + memcmp(".drectve", §ion.name, 8) != 0 || section.number_of_relocations != 0 || + section.number_of_line_numbers != 0) { continue; } // read the actual directive - std::string directive; + std::string directive_command_line; const auto section_offset = coff_base + section.pointer_to_raw_data; Checks::check_exit(VCPKG_LINE_INFO, f.seek(section_offset, SEEK_SET) == 0); - directive.resize(section.size_of_raw_data); - auto fun = f.read(directive.data(), 1, section.size_of_raw_data); - Checks::check_exit(VCPKG_LINE_INFO, - fun == - section.size_of_raw_data); + directive_command_line.resize(section.size_of_raw_data); + auto fun = f.read(directive_command_line.data(), 1, section.size_of_raw_data); + Checks::check_exit(VCPKG_LINE_INFO, fun == section.size_of_raw_data); - if (Strings::starts_with(directive, StringLiteral{"\xEF\xBB\xBF"})) + if (Strings::starts_with(directive_command_line, StringLiteral{"\xEF\xBB\xBF"})) { - // chop of the BOM - directive.erase(0, 3); + // chop off the BOM + directive_command_line.erase(0, 3); } - auto insertion_point = std::lower_bound(directives.begin(), directives.end(), directive); - if (insertion_point == directives.end() || *insertion_point != directive) + for (auto&& directive : tokenize_command_line(directive_command_line)) { - directives.insert(insertion_point, std::move(directive)); + auto insertion_point = + std::lower_bound(directives.begin(), directives.end(), directive_command_line); + if (insertion_point == directives.end() || *insertion_point != directive) + { + directives.insert(insertion_point, std::move(directive)); + } } } } @@ -453,6 +454,87 @@ namespace vcpkg return value; } + static void handle_uninteresting_command_line_ch(char ch, size_t& slash_count, std::string& this_arg) + { + // n backslashes not followed by a quotation mark produce n backslashes + if (slash_count) + { + this_arg.append(slash_count, '\\'); + slash_count = 0; + } + + this_arg.push_back(ch); + } + + static void handle_maybe_adding_argument(std::vector& result, std::string& this_arg) + { + if (!this_arg.empty()) + { + result.push_back(std::move(this_arg)); + this_arg.clear(); + } + } + + std::vector tokenize_command_line(StringView cmd_line) + { + std::vector result; + std::string this_arg; + bool in_quoted_argument = false; + std::size_t slash_count = 0; + for (auto&& ch : cmd_line) + { + if (ch == '\\') + { + ++slash_count; + } + else if (ch == '"') + { + // 2n backslashes followed by a quotation mark produce n backslashes followed by an (ending) quotation + // mark + // + // 2n + 1 backslashes followed by a quotation mark produce n backslashes followed by an (escaped) + // quotation mark + if (slash_count) + { + this_arg.append(slash_count >> 1, '\\'); + if (std::exchange(slash_count, std::size_t{}) & 0x1u) + { + // escaped + handle_uninteresting_command_line_ch('"', slash_count, this_arg); + } + else + { + // not escaped + in_quoted_argument = !in_quoted_argument; + } + } + else + { + in_quoted_argument = !in_quoted_argument; + } + } + else if (ParserBase::is_whitespace(ch)) + { + if (in_quoted_argument) + { + handle_uninteresting_command_line_ch(ch, slash_count, this_arg); + } + else + { + handle_maybe_adding_argument(result, this_arg); + } + } + else + { + handle_uninteresting_command_line_ch(ch, slash_count, this_arg); + } + } + + this_arg.append(slash_count, '\\'); + handle_maybe_adding_argument(result, this_arg); + return result; + } + ExpectedL try_read_dll_metadata(ReadFilePointer& f) { { @@ -600,7 +682,7 @@ namespace vcpkg read_and_verify_archive_file_signature(f); read_and_skip_first_linker_member(f); const auto offsets = read_second_linker_member_offsets(f); - return read_machine_types_from_archive_members(f, offsets); + return read_lib_information_from_archive_members(f, offsets); } MachineType to_machine_type(const uint16_t value) diff --git a/src/vcpkg/base/messages.cpp b/src/vcpkg/base/messages.cpp index 947d102a8f..1ee96c6750 100644 --- a/src/vcpkg/base/messages.cpp +++ b/src/vcpkg/base/messages.cpp @@ -801,6 +801,10 @@ namespace vcpkg REGISTER_MESSAGE(LicenseExpressionImbalancedParens); REGISTER_MESSAGE(LicenseExpressionUnknownException); REGISTER_MESSAGE(LicenseExpressionUnknownLicense); + REGISTER_MESSAGE(LinkageDynamicDebug); + REGISTER_MESSAGE(LinkageDynamicRelease); + REGISTER_MESSAGE(LinkageStaticDebug); + REGISTER_MESSAGE(LinkageStaticRelease); REGISTER_MESSAGE(ListOfValidFieldsForControlFiles); REGISTER_MESSAGE(LoadingCommunityTriplet); REGISTER_MESSAGE(LoadingDependencyInformation); @@ -1070,6 +1074,7 @@ namespace vcpkg REGISTER_MESSAGE(PortBugMovePkgConfigFiles); REGISTER_MESSAGE(PortBugRemoveEmptyDirs); REGISTER_MESSAGE(PortBugInvalidCrtLinkage); + REGISTER_MESSAGE(PortBugInvalidCrtLinkageEntry); REGISTER_MESSAGE(PortBugInspectFiles); REGISTER_MESSAGE(PortBugOutdatedCRT); REGISTER_MESSAGE(PortBugMisplacedFiles); diff --git a/src/vcpkg/build.cpp b/src/vcpkg/build.cpp index 7c80e91d69..198feea56d 100644 --- a/src/vcpkg/build.cpp +++ b/src/vcpkg/build.cpp @@ -968,7 +968,7 @@ namespace vcpkg const BuildInfo build_info = read_build_info(fs, paths.build_info_file_path(action.spec)); const size_t error_count = - PostBuildLint::perform_all_checks(action.spec, paths, pre_build_info, build_info, scfl.source_location); + perform_post_build_lint_checks(action.spec, paths, pre_build_info, build_info, scfl.source_location); auto find_itr = action.feature_dependencies.find("core"); Checks::check_exit(VCPKG_LINE_INFO, find_itr != action.feature_dependencies.end()); diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index 05d90230d7..709985a412 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -10,7 +10,7 @@ #include #include -namespace vcpkg::PostBuildLint +namespace vcpkg { constexpr static const StringLiteral windows_system_names[] = { "", @@ -855,6 +855,34 @@ namespace vcpkg::PostBuildLint bool has_dynamic_debug = false; }; + static LocalizedString format_linkage(LinkageType linkage, bool release) + { + switch (linkage) + { + case LinkageType::DYNAMIC: + if (release) + { + return msg::format(msgLinkageDynamicRelease); + } + else + { + return msg::format(msgLinkageDynamicDebug); + } + break; + case LinkageType::STATIC: + if (release) + { + return msg::format(msgLinkageStaticRelease); + } + else + { + return msg::format(msgLinkageStaticRelease); + } + break; + default: Checks::unreachable(VCPKG_LINE_INFO); + } + } + static LintStatus check_crt_linkage_of_libs(const Filesystem& fs, const BuildInfo& build_info, bool expect_release, @@ -871,10 +899,10 @@ namespace vcpkg::PostBuildLint " has directives: " + Strings::join(" ", lib_info.linker_directives)); BuildTypeAndFile this_lib{lib}; - constexpr static const StringLiteral static_release_crt = "/DEFAULTLIB:\"LIBCMT\""; - constexpr static const StringLiteral static_debug_crt = "/DEFAULTLIB:\"LIBCMTd\""; - constexpr static const StringLiteral dynamic_release_crt = "/DEFAULTLIB:\"MSVCRT\""; - constexpr static const StringLiteral dynamic_debug_crt = "/DEFAULTLIB:\"MSVCRTd\""; + constexpr static const StringLiteral static_release_crt = "/DEFAULTLIB:LIBCMT"; + constexpr static const StringLiteral static_debug_crt = "/DEFAULTLIB:LIBCMTd"; + constexpr static const StringLiteral dynamic_release_crt = "/DEFAULTLIB:MSVCRT"; + constexpr static const StringLiteral dynamic_debug_crt = "/DEFAULTLIB:MSVCRTd"; for (auto&& directive : lib_info.linker_directives) { @@ -895,22 +923,96 @@ namespace vcpkg::PostBuildLint this_lib.has_dynamic_debug = true; } } + + bool fail = false; + if (expect_release) + { + fail |= this_lib.has_static_debug; + fail |= this_lib.has_dynamic_debug; + } + else + { + fail |= this_lib.has_static_release; + fail |= this_lib.has_dynamic_release; + } + + switch (build_info.crt_linkage) + { + case LinkageType::DYNAMIC: + fail |= this_lib.has_static_debug; + fail |= this_lib.has_static_release; + break; + case LinkageType::STATIC: + fail |= this_lib.has_dynamic_debug; + fail |= this_lib.has_dynamic_release; + break; + default: Checks::unreachable(VCPKG_LINE_INFO); + } + + if (fail) + { + libs_with_invalid_crt.push_back(std::move(this_lib)); + } } - // if (!libs_with_invalid_crt.empty()) - //{ - // msg::println_warning(msgPortBugInvalidCrtLinkage, msg::expected = expected_build_type.to_string()); + if (!libs_with_invalid_crt.empty()) + { + msg::println_warning(msgPortBugInvalidCrtLinkage, + msg::expected = format_linkage(build_info.crt_linkage, expect_release)); + for (const BuildTypeAndFile& btf : libs_with_invalid_crt) + { + msg::print( + LocalizedString().append_indent().append(msgPortBugInvalidCrtLinkageEntry, msg::path = btf.file)); + if ((btf.has_dynamic_debug + btf.has_dynamic_release + btf.has_static_debug + btf.has_static_release) == + 1) + { + // reasonable lib that tries to link with but one CRT + if (btf.has_dynamic_debug) + { + msg::println(msgLinkageDynamicDebug); + } + else if (btf.has_dynamic_release) + { + msg::println(msgLinkageDynamicRelease); + } + else if (btf.has_static_debug) + { + msg::println(msgLinkageStaticDebug); + } + else + { + msg::println(msgLinkageStaticRelease); + } + } + else + { + msg::println(); + if (btf.has_dynamic_debug) + { + msg::println(LocalizedString().append_indent(2).append(msgLinkageDynamicDebug)); + } + + if (btf.has_dynamic_release) + { + msg::println(LocalizedString().append_indent(2).append(msgLinkageDynamicRelease)); + } - // for (const BuildTypeAndFile& btf : libs_with_invalid_crt) - // { - // msg::write_unlocalized_text_to_stdout( - // Color::warning, fmt::format(" {}: {}\n", btf.file, btf.build_type.to_string())); - // } + if (btf.has_static_debug) + { + msg::println(LocalizedString().append_indent(2).append(msgLinkageStaticDebug)); + } - // msg::println_warning(msg::format(msgPortBugInspectFiles, msg::extension = "lib") - // .append_raw("\n dumpbin.exe /directives mylibfile.lib")); - // return LintStatus::PROBLEM_DETECTED; - //} + if (btf.has_static_release) + { + msg::println(LocalizedString().append_indent(2).append(msgLinkageStaticRelease)); + } + } + } + + msg::println_warning(msg::format(msgPortBugInspectFiles, msg::extension = "lib") + .append_raw("\n dumpbin.exe /directives mylibfile.lib")); + return LintStatus::PROBLEM_DETECTED; + } return LintStatus::SUCCESS; } @@ -1120,11 +1222,11 @@ namespace vcpkg::PostBuildLint return error_count; } - size_t perform_all_checks(const PackageSpec& spec, - const VcpkgPaths& paths, - const PreBuildInfo& pre_build_info, - const BuildInfo& build_info, - const Path& port_dir) + size_t perform_post_build_lint_checks(const PackageSpec& spec, + const VcpkgPaths& paths, + const PreBuildInfo& pre_build_info, + const BuildInfo& build_info, + const Path& port_dir) { msg::println(msgPerformingPostBuildValidation); const size_t error_count = perform_all_checks_and_return_error_count(spec, paths, pre_build_info, build_info); From d76e94cbb0e257d99f18d8f6b9167ba592cf9710 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 15 Dec 2022 04:46:51 -0500 Subject: [PATCH 07/33] Add a both test case and fix bad extra newlines. --- .../build.cmd | 4 +- .../portfile.cmake | 2 + .../test-lib-port-template-dynamic-crt/test.c | 6 +- .../post-build-checks.ps1 | 22 ++++--- src/vcpkg/postbuildlint.cpp | 61 ++++++++----------- 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/build.cmd b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/build.cmd index e1a39e9128..a50bd2aad8 100644 --- a/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/build.cmd +++ b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/build.cmd @@ -1,6 +1,8 @@ mkdir "%~dp0debug" mkdir "%~dp0release" +mkdir "%~dp0both" cl /c /MDd "%~dp0test.c" /Fo"%~dp0debug\test.obj" lib "%~dp0debug\test.obj" /OUT:"%~dp0debug\test_lib.lib" -cl /c /MD "%~dp0test.c" /Fo"%~dp0release\test.obj" +cl /c /DNDEBUG /MD "%~dp0test.c" /Fo"%~dp0release\test.obj" lib "%~dp0release\test.obj" /OUT:"%~dp0release\test_lib.lib" +lib "%~dp0debug\test.obj" "%~dp0release\test.obj" /OUT:"%~dp0both\both_lib.lib" diff --git a/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/portfile.cmake b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/portfile.cmake index 7b9a9e06a6..d902620688 100644 --- a/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/portfile.cmake +++ b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/portfile.cmake @@ -5,6 +5,8 @@ file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/include") file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share") file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share/${PORT}") file(COPY "${CMAKE_CURRENT_LIST_DIR}/debug/test_lib.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/debug/lib") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/both/both_lib.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/debug/lib") file(COPY "${CMAKE_CURRENT_LIST_DIR}/release/test_lib.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/lib") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/both/both_lib.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/lib") file(COPY "${CMAKE_CURRENT_LIST_DIR}/test.h" DESTINATION "${CURRENT_PACKAGES_DIR}/include") file(TOUCH "${CURRENT_PACKAGES_DIR}/share/${PORT}/copyright") diff --git a/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.c b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.c index 608e24b4cd..e7a6cf2fe8 100644 --- a/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.c +++ b/azure-pipelines/e2e_assets/test-lib-port-template-dynamic-crt/test.c @@ -1,6 +1,10 @@ #include -int __cdecl use_me() { +#ifdef NDEBUG +int __cdecl use_ndebug() { +#else +int __cdecl use_no_ndebug() { +#endif puts("You called the static lib function!"); return 42; } diff --git a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 index a5325dfbd5..8f88837d02 100644 --- a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 @@ -73,14 +73,20 @@ Copy-Item -Recurse "$PSScriptRoot/../e2e_assets/test-lib-port-template-dynamic-c Run-Vcpkg env "$WorkingRoot/wrong-crt/test-lib/build.cmd" --Triplet x86-windows-static Throw-IfFailed -$buildOutput = Run-VcpkgAndCaptureOutput --triplet x86-windows-static "--x-buildtrees-root=$buildtreesRoot" "--x-install-root=$installRoot" "--x-packages-root=$packagesRoot" install --overlay-ports="$WorkingRoot/wrong-crt" test-lib --no-binarycaching --debug -$expected = "warning: Invalid crt linkage. Expected Debug,Static, but the following libs had:`n" + ` -" $packagesRoot\test-lib_x86-windows-static\debug\lib\test_lib.lib: Debug,Dynamic`n" + ` -"warning: To inspect the lib files, use:`n" + ` -" dumpbin.exe /directives mylibfile.lib`n" + ` -"warning: Invalid crt linkage. Expected Release,Static, but the following libs had:`n" + ` -" $packagesRoot\test-lib_x86-windows-static\lib\test_lib.lib: Release,Dynamic`n" + ` -"warning: To inspect the lib files, use:`n" + ` +$buildOutput = Run-VcpkgAndCaptureOutput --triplet x86-windows-static "--x-buildtrees-root=$buildtreesRoot" "--x-install-root=$installRoot" "--x-packages-root=$packagesRoot" install --overlay-ports="$WorkingRoot/wrong-crt" test-lib --no-binarycaching +$expected = "warning: The following binaries should use the Static Release CRT.`n" + +" $packagesRoot\test-lib_x86-windows-static\debug\lib\both_lib.lib links with:`n" + +" Dynamic Debug`n" + +" Dynamic Release`n" + +" $packagesRoot\test-lib_x86-windows-static\debug\lib\test_lib.lib links with: Dynamic Debug`n" + +"To inspect the lib files, use:`n" + +" dumpbin.exe /directives mylibfile.lib`n" + +"warning: The following binaries should use the Static Release CRT.`n" + +" $packagesRoot\test-lib_x86-windows-static\lib\both_lib.lib links with:`n" + +" Dynamic Debug`n" + +" Dynamic Release`n" + +" $packagesRoot\test-lib_x86-windows-static\lib\test_lib.lib links with: Dynamic Release`n" + +"To inspect the lib files, use:`n" + " dumpbin.exe /directives mylibfile.lib`n" if (-not $buildOutput.Replace("`r`n", "`n").Contains($expected)) { throw 'Did not detect lib with wrong CRT linkage.' diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index 709985a412..a03adf0c79 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -963,54 +963,41 @@ namespace vcpkg { msg::print( LocalizedString().append_indent().append(msgPortBugInvalidCrtLinkageEntry, msg::path = btf.file)); + LocalizedString prefix; if ((btf.has_dynamic_debug + btf.has_dynamic_release + btf.has_static_debug + btf.has_static_release) == 1) { - // reasonable lib that tries to link with but one CRT - if (btf.has_dynamic_debug) - { - msg::println(msgLinkageDynamicDebug); - } - else if (btf.has_dynamic_release) - { - msg::println(msgLinkageDynamicRelease); - } - else if (btf.has_static_debug) - { - msg::println(msgLinkageStaticDebug); - } - else - { - msg::println(msgLinkageStaticRelease); - } + prefix.append_raw(" "); } else { msg::println(); - if (btf.has_dynamic_debug) - { - msg::println(LocalizedString().append_indent(2).append(msgLinkageDynamicDebug)); - } + prefix.append_indent(2); + } - if (btf.has_dynamic_release) - { - msg::println(LocalizedString().append_indent(2).append(msgLinkageDynamicRelease)); - } + if (btf.has_dynamic_debug) + { + msg::println(LocalizedString(prefix).append(msgLinkageDynamicDebug)); + } - if (btf.has_static_debug) - { - msg::println(LocalizedString().append_indent(2).append(msgLinkageStaticDebug)); - } + if (btf.has_dynamic_release) + { + msg::println(LocalizedString(prefix).append(msgLinkageDynamicRelease)); + } - if (btf.has_static_release) - { - msg::println(LocalizedString().append_indent(2).append(msgLinkageStaticRelease)); - } + if (btf.has_static_debug) + { + msg::println(LocalizedString(prefix).append(msgLinkageStaticDebug)); + } + + if (btf.has_static_release) + { + msg::println(LocalizedString(prefix).append(msgLinkageStaticRelease)); } } - msg::println_warning(msg::format(msgPortBugInspectFiles, msg::extension = "lib") - .append_raw("\n dumpbin.exe /directives mylibfile.lib")); + msg::println(msg::format(msgPortBugInspectFiles, msg::extension = "lib") + .append_raw("\n dumpbin.exe /directives mylibfile.lib")); return LintStatus::PROBLEM_DETECTED; } @@ -1052,8 +1039,8 @@ namespace vcpkg msg::write_unlocalized_text_to_stdout(Color::warning, fmt::format(" {}:{}\n", btf.file, btf.outdated_crt.name)); } - msg::println_warning(msg::format(msgPortBugInspectFiles, msg::extension = "dll") - .append_raw("\n dumpbin.exe /dependents mylibfile.dll")); + msg::println(msg::format(msgPortBugInspectFiles, msg::extension = "dll") + .append_raw("\n dumpbin.exe /dependents mylibfile.dll")); return LintStatus::PROBLEM_DETECTED; } From aceae2ac0980081f704149874145baebfc58b7db Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 15 Dec 2022 07:54:17 -0500 Subject: [PATCH 08/33] Fill in the URI. --- include/vcpkg/base/messages.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/vcpkg/base/messages.h b/include/vcpkg/base/messages.h index 762f77cf5e..bf4918cd4a 100644 --- a/include/vcpkg/base/messages.h +++ b/include/vcpkg/base/messages.h @@ -2093,8 +2093,9 @@ namespace vcpkg (msg::expected), "{expected} is one of LinkageDynamicDebug/LinkageDynamicRelease/LinkageStaticDebug/LinkageStaticRelease. " "Immediately after this message is a file by file list with what linkages they contain. 'CRT' is an acronym " - "meaning C Runtime. FIXME add link to /MT/MTd/MD/MDd switch docs here. This is complicated because a binary " - "can link with more than one CRT.\n" + "meaning C Runtime. See also: " + "https://learn.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=msvc-170. This is " + "complicated because a binary can link with more than one CRT.\n" "Example fully formatted message:\n" "The following binaries should use the Dynamic Debug CRT.\n" " C:\\some\\path\\to\\sane\\lib links with: Dynamic Release\n" From dade3117b313c873060ffcb34e385f70f24f6ae9 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 15 Dec 2022 07:54:32 -0500 Subject: [PATCH 09/33] Messages --- locales/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/messages.json b/locales/messages.json index d0add3cf95..e2b0026981 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -930,7 +930,7 @@ "PortBugInspectFiles": "To inspect the {extension} files, use:", "_PortBugInspectFiles.comment": "An example of {extension} is .exe.", "PortBugInvalidCrtLinkage": "The following binaries should use the {expected} CRT.", - "_PortBugInvalidCrtLinkage.comment": "{expected} is one of LinkageDynamicDebug/LinkageDynamicRelease/LinkageStaticDebug/LinkageStaticRelease. Immediately after this message is a file by file list with what linkages they contain. 'CRT' is an acronym meaning C Runtime. FIXME add link to /MT/MTd/MD/MDd switch docs here. This is complicated because a binary can link with more than one CRT.\nExample fully formatted message:\nThe following binaries should use the Dynamic Debug CRT.\n C:\\some\\path\\to\\sane\\lib links with: Dynamic Release\n C:\\some\\path\\to\\lib links with:\n Static Debug\n Dynamic Release\n C:\\some\\different\\path\\to\\a\\dll links with:\n Static Debug\n Dynamic Debug\n", + "_PortBugInvalidCrtLinkage.comment": "{expected} is one of LinkageDynamicDebug/LinkageDynamicRelease/LinkageStaticDebug/LinkageStaticRelease. Immediately after this message is a file by file list with what linkages they contain. 'CRT' is an acronym meaning C Runtime. See also: https://learn.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=msvc-170. This is complicated because a binary can link with more than one CRT.\nExample fully formatted message:\nThe following binaries should use the Dynamic Debug CRT.\n C:\\some\\path\\to\\sane\\lib links with: Dynamic Release\n C:\\some\\path\\to\\lib links with:\n Static Debug\n Dynamic Release\n C:\\some\\different\\path\\to\\a\\dll links with:\n Static Debug\n Dynamic Debug\n", "PortBugInvalidCrtLinkageEntry": "{path} links with:", "_PortBugInvalidCrtLinkageEntry.comment": "See explanation in PortBugInvalidCrtLinkage An example of {path} is /foo/bar.", "PortBugMergeLibCMakeDir": "The /lib/cmake folder should be merged with /debug/lib/cmake and moved to /share/{spec}/cmake. Please use the helper function `vcpkg_cmake_config_fixup()` from the port vcpkg-cmake-config.`", From fe4888c2af52f7d211f840a887b203e62a5e294e Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 15 Dec 2022 08:01:04 -0500 Subject: [PATCH 10/33] Rip out looking for dumpbin elsewhere. --- include/vcpkg/vcpkgpaths.h | 1 - src/vcpkg/postbuildlint.cpp | 12 +++---- src/vcpkg/vcpkgpaths.cpp | 17 +++++----- src/vcpkg/visualstudio.cpp | 63 +++++++++++++++---------------------- 4 files changed, 37 insertions(+), 56 deletions(-) diff --git a/include/vcpkg/vcpkgpaths.h b/include/vcpkg/vcpkgpaths.h index 9e2c7b2ed3..56352f2dda 100644 --- a/include/vcpkg/vcpkgpaths.h +++ b/include/vcpkg/vcpkgpaths.h @@ -36,7 +36,6 @@ namespace vcpkg struct Toolset { Path visual_studio_root_path; - Path dumpbin; Path vcvarsall; std::vector vcvarsall_options; ZStringView version; diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index a03adf0c79..c0c35694f5 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -1186,16 +1186,12 @@ namespace vcpkg error_count += check_no_dlls_present(build_info.policies, dlls); error_count += check_bin_folders_are_not_present_in_static_build(build_info.policies, fs, package_dir); - - if (!toolset.dumpbin.empty() && !build_info.policies.is_enabled(BuildPolicy::SKIP_DUMPBIN_CHECKS)) + if (!build_info.policies.is_enabled(BuildPolicy::ONLY_RELEASE_CRT)) { - if (!build_info.policies.is_enabled(BuildPolicy::ONLY_RELEASE_CRT)) - { - error_count += check_crt_linkage_of_libs(fs, build_info, false, debug_libs); - } - - error_count += check_crt_linkage_of_libs(fs, build_info, true, release_libs); + error_count += check_crt_linkage_of_libs(fs, build_info, false, debug_libs); } + + error_count += check_crt_linkage_of_libs(fs, build_info, true, release_libs); break; } default: Checks::unreachable(VCPKG_LINE_INFO); diff --git a/src/vcpkg/vcpkgpaths.cpp b/src/vcpkg/vcpkgpaths.cpp index 1431b54b7b..2aafb3209f 100644 --- a/src/vcpkg/vcpkgpaths.cpp +++ b/src/vcpkg/vcpkgpaths.cpp @@ -1333,16 +1333,13 @@ namespace vcpkg { if (!prebuildinfo.using_vcvars()) { - static Toolset external_toolset = []() -> Toolset { - Toolset ret; - ret.dumpbin.clear(); - ret.supported_architectures = {ToolsetArchOption{"", get_host_processor(), get_host_processor()}}; - ret.vcvarsall.clear(); - ret.vcvarsall_options = {}; - ret.version = "external"; - ret.visual_studio_root_path.clear(); - return ret; - }(); + static const Toolset external_toolset{ + Path{}, + Path{}, + std::vector{}, + "external", + std::string{}, + std::vector{ToolsetArchOption{"", get_host_processor(), get_host_processor()}}}; return external_toolset; } diff --git a/src/vcpkg/visualstudio.cpp b/src/vcpkg/visualstudio.cpp index b2cba33cfd..74f5101a2e 100644 --- a/src/vcpkg/visualstudio.cpp +++ b/src/vcpkg/visualstudio.cpp @@ -279,33 +279,26 @@ namespace vcpkg::VisualStudio // unknown toolset minor version continue; } - const auto dumpbin_dir = subdir / "bin/HostX86/x86"; - const auto dumpbin_path = dumpbin_dir / "dumpbin.exe"; - paths_examined.push_back(dumpbin_path); - if (fs.exists(dumpbin_path, IgnoreErrors{})) - { - Toolset toolset{vs_instance.root_path, - dumpbin_path, - vcvarsall_bat, - {vcvars_option}, - toolset_version, - toolset_version_full.to_string(), - supported_architectures}; - - found_toolsets.push_back(std::move(toolset)); - if (v140_is_available) - { - found_toolsets.push_back({vs_instance.root_path, - dumpbin_path, - vcvarsall_bat, - {"-vcvars_ver=14.0"}, - V_140, - "14", - supported_architectures}); - } - continue; + Toolset toolset{vs_instance.root_path, + vcvarsall_bat, + {vcvars_option}, + toolset_version, + toolset_version_full.to_string(), + supported_architectures}; + + found_toolsets.push_back(std::move(toolset)); + if (v140_is_available) + { + found_toolsets.push_back({vs_instance.root_path, + vcvarsall_bat, + {"-vcvars_ver=14.0"}, + V_140, + "14", + supported_architectures}); } + + continue; } continue; @@ -337,18 +330,14 @@ namespace vcpkg::VisualStudio if (fs.exists(vs_bin_dir / "amd64_arm/vcvarsamd64_arm.bat", IgnoreErrors{})) supported_architectures.push_back({"amd64_arm", CPU::X64, CPU::ARM}); - if (fs.exists(vs_dumpbin_exe, IgnoreErrors{})) - { - const Toolset toolset = {vs_instance.root_path, - vs_dumpbin_exe, - vcvarsall_bat, - {}, - major_version == "14" ? V_140 : V_120, - major_version, - supported_architectures}; - - found_toolsets.push_back(toolset); - } + const Toolset toolset = {vs_instance.root_path, + vcvarsall_bat, + {}, + major_version == "14" ? V_140 : V_120, + major_version, + supported_architectures}; + + found_toolsets.push_back(toolset); } } } From b60e19ef93c1d92d23f9ae58df3e760f2b2235d9 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 15 Dec 2022 08:08:00 -0500 Subject: [PATCH 11/33] Unused local. --- src/vcpkg/postbuildlint.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index c0c35694f5..725620914b 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -1074,7 +1074,6 @@ namespace vcpkg const BuildInfo& build_info) { const auto& fs = paths.get_filesystem(); - const Toolset& toolset = paths.get_toolset(pre_build_info); const auto package_dir = paths.package_dir(spec); size_t error_count = 0; From 24daad28d22538f0a75e29560e8c41e7195906b0 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 3 Jan 2023 00:53:05 -0500 Subject: [PATCH 12/33] Add the ability to read the first linker member in archives. This happened in https://github.com/microsoft/vcpkg/issues/14322 --- src/vcpkg/base/cofffilereader.cpp | 97 ++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 13 deletions(-) diff --git a/src/vcpkg/base/cofffilereader.cpp b/src/vcpkg/base/cofffilereader.cpp index eff5c9f229..5d6dbe19e0 100644 --- a/src/vcpkg/base/cofffilereader.cpp +++ b/src/vcpkg/base/cofffilereader.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -270,7 +271,12 @@ namespace } } - void read_and_skip_first_linker_member(const vcpkg::ReadFilePointer& f) + uint32_t bswap(uint32_t value) + { + return (value >> 24) | ((value & 0x00FF0000u) >> 8) | ((value & 0x0000FF00u) << 8) | (value << 24); + } + + Optional> try_read_first_linker_member_offsets(const vcpkg::ReadFilePointer& f) { ArchiveMemberHeader first_linker_member_header; Checks::check_exit(VCPKG_LINE_INFO, @@ -278,13 +284,53 @@ namespace if (memcmp(first_linker_member_header.name, "/ ", 2) != 0) { Debug::println("Could not find proper first linker member"); - Checks::exit_fail(VCPKG_LINE_INFO); + return nullopt; } - Checks::check_exit(VCPKG_LINE_INFO, f.seek(first_linker_member_header.decoded_size(), SEEK_CUR) == 0); + auto first_size = first_linker_member_header.decoded_size(); + uint32_t archive_symbol_count; + if (first_size < sizeof(archive_symbol_count)) + { + Debug::println("Firstlinker member was too small to contain a single uint32_t"); + return nullopt; + } + + if (f.read(&archive_symbol_count, sizeof(archive_symbol_count), 1) != 1) + { + Debug::println("Could not read first linker member."); + return nullopt; + } + + archive_symbol_count = bswap(archive_symbol_count); + const auto maximum_possible_archive_members = (first_size / sizeof(uint32_t)) - 1; + if (archive_symbol_count > maximum_possible_archive_members) + { + Debug::println("First linker member was too small to contain the expected number of symbols"); + return nullopt; + } + + std::vector offsets(archive_symbol_count); + if (f.read(offsets.data(), sizeof(uint32_t), archive_symbol_count) != archive_symbol_count) + { + Debug::println("Could not read first linker member offsets."); + return nullopt; + } + + // convert (big endian) offsets to little endian + for (auto&& offset : offsets) + { + offset = bswap(offset); + } + + Util::sort_unique_erase(offsets); + offsets.erase(std::remove(offsets.begin(), offsets.end(), 0u), offsets.end()); + std::sort(offsets.begin(), offsets.end()); + uint64_t leftover = first_size - sizeof(uint32_t) - (archive_symbol_count * sizeof(uint32_t)); + Checks::check_exit(VCPKG_LINE_INFO, f.seek(leftover, SEEK_CUR) == 0); + return offsets; } - std::vector read_second_linker_member_offsets(const vcpkg::ReadFilePointer& f) + Optional> try_read_second_linker_member_offsets(const vcpkg::ReadFilePointer& f) { ArchiveMemberHeader second_linker_member_header; Checks::check_exit(VCPKG_LINE_INFO, @@ -292,7 +338,7 @@ namespace if (memcmp(second_linker_member_header.name, "/ ", 2) != 0) { Debug::println("Could not find proper second linker member"); - Checks::exit_fail(VCPKG_LINE_INFO); + return nullopt; } const auto second_size = second_linker_member_header.decoded_size(); @@ -302,20 +348,28 @@ namespace if (second_size < sizeof(archive_member_count)) { Debug::println("Second linker member was too small to contain a single uint32_t"); - Checks::exit_fail(VCPKG_LINE_INFO); + return nullopt; + } + + if (f.read(&archive_member_count, sizeof(archive_member_count), 1) != 1) + { + Debug::println("Failed to read second linker member member count."); + return nullopt; } - Checks::check_exit(VCPKG_LINE_INFO, f.read(&archive_member_count, sizeof(archive_member_count), 1) == 1); const auto maximum_possible_archive_members = (second_size / sizeof(uint32_t)) - 1; if (archive_member_count > maximum_possible_archive_members) { Debug::println("Second linker member was too small to contain the expected number of archive members"); - Checks::exit_fail(VCPKG_LINE_INFO); + return nullopt; } std::vector offsets(archive_member_count); - Checks::check_exit(VCPKG_LINE_INFO, - f.read(offsets.data(), sizeof(uint32_t), archive_member_count) == archive_member_count); + if (f.read(offsets.data(), sizeof(uint32_t), archive_member_count) != archive_member_count) + { + Debug::println("Failed to read second linker member offsets"); + return nullopt; + } // Ignore offsets that point to offset 0. See vcpkg github #223 #288 #292 offsets.erase(std::remove(offsets.begin(), offsets.end(), 0u), offsets.end()); @@ -680,9 +734,26 @@ namespace vcpkg LibInformation read_lib_information(const ReadFilePointer& f) { read_and_verify_archive_file_signature(f); - read_and_skip_first_linker_member(f); - const auto offsets = read_second_linker_member_offsets(f); - return read_lib_information_from_archive_members(f, offsets); + const auto first_offsets = try_read_first_linker_member_offsets(f); + const auto second_offsets = try_read_second_linker_member_offsets(f); + const std::vector* offsets; + // "Although both linker members provide a directory of symbols and archive members that + // contain them, the second linker member is used in preference to the first by all current linkers." + if (auto maybe_offsets2 = second_offsets.get()) + { + offsets = maybe_offsets2; + } + else if (auto maybe_offsets = first_offsets.get()) + { + offsets = maybe_offsets; + } + else + { + // FIXME message + Checks::exit_fail(VCPKG_LINE_INFO); + } + + return read_lib_information_from_archive_members(f, *offsets); } MachineType to_machine_type(const uint16_t value) From 6fc321cb159ddfb14b4a157bcf163b08ad88d05f Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 9 Jan 2023 15:40:24 -0800 Subject: [PATCH 13/33] Add end to end test with an LLVM LTO lib and clean up the mismatched debug and release binaries output. See https://github.com/microsoft/vcpkg-tool/pull/834#issuecomment-1376496817 for examples. --- .../llvm-lto-lib/llvm-lto-charset.lib | Bin 0 -> 16084 bytes .../e2e_ports/llvm-lto-lib/portfile.cmake | 12 ++++++++++ .../e2e_ports/llvm-lto-lib/vcpkg.json | 5 +++++ .../end-to-end-tests-dir/regression-ports.ps1 | 6 +++++ include/vcpkg/base/messages.h | 2 +- src/vcpkg/postbuildlint.cpp | 21 ++++++++++++------ 6 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 azure-pipelines/e2e_ports/llvm-lto-lib/llvm-lto-charset.lib create mode 100644 azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake create mode 100644 azure-pipelines/e2e_ports/llvm-lto-lib/vcpkg.json create mode 100644 azure-pipelines/end-to-end-tests-dir/regression-ports.ps1 diff --git a/azure-pipelines/e2e_ports/llvm-lto-lib/llvm-lto-charset.lib b/azure-pipelines/e2e_ports/llvm-lto-lib/llvm-lto-charset.lib new file mode 100644 index 0000000000000000000000000000000000000000..d7c616618a2fc55c4dfca3834cc7bf37ebdf5529 GIT binary patch literal 16084 zcmeHueSA|z*6`dUP0}_^QW{H2(|A(~7MGUWqzy?wBp-YPED}DqV%_GO7W)y}6bk!w z(-cy)YQU~mm)$3I5pfsYss)i{pEqeL7VKgdQ7hYrHwe_qqIMB|*j;z`J#&+kqQ36) z?z8V7&+oVQm)w~-b7tnunKLtI&YY_#w>H~r?@C!f-uh6}lCk*oH%Y1}WgNqjf)Ii~ zG4}WWMPIbIo9h}qE>z!Sx7Isr?6ubB7N-Z*)G&aW7LTK@sV0U~)8zKlH8r-NMT=^T zx*DqZ9+SbeymFOEXEZO$GcIjel&9D0rgE1XmfT}pxy%sHZM`M8WR+>9afNBc3Z1%y zqKa%U9|v@7Aqfw{(&AOPNOFJ(bH%OIPXiYmLj7 z#|qZh+2VbwfqvCAJ8{2oH=t8aS6v%I3%<t z#+$L)>YW8Go>p5dW5M)6gi59-r;nz(xR`08NU2oE;Fc7FF?7B}f>06+u1!GYt+@B! zT|fDA|1VQl)0G6k6as{tFzTr+1!6%u6aGB!>^=G+&T_6;sohI-2<9a5v*etIY_wzv z%dj`quwSf{X!z2*QwnVb^- zDY1F)fzBCof5>Xzd1JTh!M?oir)RnzL6UKPC?rfq8FV^QQ5-Hy5Z>3~LdiV@?ci`K z1H%DCu~CRG=$Wmc5!z)!q-uZnIKO=!w7*)4&_d{J_W9X2{ss?0qIrC_m*Q>b`?u!% z)wF+`iMK82Zw~N6Ip@PUrwH<#B4?~OZM0W*S|Jd|*UQgEcx|-b)-xk`x15Fa5tHHFZv=Ft+2lVpOy|Rhk zwBcUafLDG+4^_$O5-D%H)UOS&)m6SNAzrz~S3>c=*TdTmky`)O5KmpjZfoPUNug^H z_igX-H$zsBe|tVp8;|%C5nid=r%B|Ny4i6!6zPHb+20HK$`F6YLEbiCmz39bkQbGm z0!HcOXRIO(t1M@i-~EFe1D>!kwHHei#*AHw&+!qmiv>oiSes4v0L^Bd88!~2(8A}7~iXa>D&;{WqBi!py2@*{Pgde+w z4I{z}I?)6g@s*#2N(ReEjGC@UX+Kdu6e$}qYP;AK$9?7fUd>sbw#TT2+J=p#6M)%< z#Mi~bYi{9Xov48lPMSsNuBbPs-&dp72RyzFuS57qB#U* zedWj5H^-~fSkdFtb_3hP<@gTNt)n1a1INEW#U<=o&;ugdfqE=O9Isl<;F6j$_^?c+LzE zWtr)wIa}K7wLKY?DXTmwBd(+M-m?dIIz`rA(NB8h{@cmn=V4dM@Z{zLA_iqXM zw*~xav401}gDJng*0vH^Vw} zkheYGza70}kzKON#&yC`OWFzI_DMSJosewOD!=4SdncH4j<_A*(F-|It8C0GhxoWv zehRWI^6_5TB|v5(6TR}WUfDT|EZQrlf&OjK1(SaZ zQcEk*d^E3~nnhHhHKTO)Y0So$xZWU0;`{#+KV~)fJL1=U2bw`kP-@VZmXe2(`_O*0 zE_>eu<|QvAq1U1>&<(bZ^(PBkkp|o*=d#G1X`Jas>R@RS(PhU$+S$5(W9d<2cArtZ%$W{*y-pW%xAZ0!gLo%>(Q!ql=5 z{5>-SQM@Mn6$MbrL3U82rbaOo3;7R_Ntbjz%*{=uo$TJfU@$UecdkUIE$nboD68Id z43SAuL3=S@E&UD(u-x42u2slHXnbj0sQ}GGoB9;VzBmr0&a;s)^!xMy?ulIv0gIN< zD*l<^XdvKa%IarHviB;*Xbn0|ntW(E=r}UabuxD8q;vU;i>#E;VF*-8CDtBl{s5(~ z>Phx0tyMj)foS`P= zwiiWK)Q5Y*^B=Jck7QO;3IWzl@EGlQGNDNwtPY_8;uoYa)%AFAwr&CK`u7&vy^KboDsgY`OcKW zci*_YefE?`FH6U*`Al1= zeG<_*Z>^{woaC-WNQV$t+`&Uvdq#a}VsAE|L88fWWHC82{VW7Hpq+;ZM2O{~K+3Xx zKq1tv12PedETg0iKE--QBFBG@}9 z-uTqFiaH*@a<_SHIO9FTn{~(Dd3r_35%+zy^Y3_Y-CpgCy-)7m6QjvAx9-YwNxWz0 zKAXft=>BP-y@QD(v^T4LuXp#JSD8|#xwV_~=OxFopiq96RF<6` zEA;qJ_qsRkk7Y51PCof!tdNVpVlMaf6UOkBu`fWPD6zkGHhPED#P0;w>4? zj6oz;Xx-|p!%-%R5ES}Rya+;p;XNZW;u#2KNo-1qt5~vGEoodJacd=>GD%y7)G zv|iF-lyokUbS;wvD9PRxlE*70Pf?P6t0ch%lBd^54y=>>e1qhLD#=S5OWPV=z5kP$ zvdl+MIzP?&$%bFP*YKa&a?H&aK?n~)sN&PI!3#2%gsA8=YC0la21fI3>DeL}N21uN zLM1TB2e7g%b5ThQnlBqp7;w~pGu&`nm&eWfE-1VvzuV2*;bw1b^SeoZ)^NJ;YCw2_ z5;anyi*On+3svI5obzx-SL6&>xv}0{CPWJ7Q{&Ml^70>}11Pb^$c{MSIycwr0^>Ag3Qku3*&?S83oqU$D*=J7jmu;a+h>9sAi@6 zd}YJtym&_}{%vrq?^#`WJs`pykZ)#83kqzy_yGa72idS9XVS`Dx6`K?j+FHoD}W(i z43u9omUTih()C&j^whr%=z(KIKCijQTYXV1yc!Z-HVZ$cW{1z{<(DqZ9KDcp9tbdH zmG${5`hD4O`0IjWaisicSPQ4^v+VL=Q~wq|52)J0oNuyzcS3m8BKj!Goh0Gli#5&9 z&B8{p@FFFI@#HW~reRlrCM>jr~4r+Ra+873@q<=H9W1w6hYsN^!p>vj^>b=Y*8xm%z23gV7kl=+O3 z2T4IhJSTIPX+^UP&pI&h;U9jrG}{*x6&5Wla4M}ODvgS=S_|#!Tv}HT&91DoH#fC3xjf{Cx|UXJJ-OD?3O3(rC8bnW8=D#$S{v&; z+p9MitJgI()dT)oh!zzWs^C|oRjI1$8twJ14kvV|xwX+#*WfIyRcReol~rTc6st7O zVhR}JQfbx2Hb+T`)1|g)TIzNoPfK+XHPyEw3V5ef zQWS*Mt@dV5wY{m?31Qqo4&&yk+f-QVu-aW(YN5?xEuo67E*oW27rRPSR%NjgU{3Wn znbm7n#mwt#Jx$HlO^luTra|7`CFJr(*Vbr`yrwVLBS?EoN+OU42tS zox|SX2E)FisS!Ah843lO9%u!lcS~zMu4lpGB}?_|E7w&nH`~cygD%lmjG$>Q@p-R}i{?dg^#i*|falx8xnVC9fl%s#-#( z9PayJsA@@+cNpy=s14~IhJtRQkFfjM=K6s=vote{d?@Wp#&^embn4JnAi>&VL` zJM(G6oT^?Z(nFH!zKwcD2V`<|ccOj(V4Yg94td1__H8GO`8Wsl!Jl-NFg?<)HS<7XQ@P1A~;(JV@FP7NBBm%KS8%!j)^qpr?fd;eswlGO&&=pznmBkRbpvFllKlX=t&~ zf|a&o3_Mhv^dh8&#ghZ3$MGOtWoba=N{ttSZWLD*L|HjEFc>OXEF94s4y1absZm6O zaugB_ETAL0q)9{+?_rk%%Cq=l3piz@gsOCwP8bqE8)2r6eUVrj6D-jAz`7ZGsFnJD zpi{-ULhYS{CEyqh*oPR+3sTTY5wufC!!Cgd?T=J;prdSRUv4LBeQNJJxSF>l9iUEA zMzLu2y#`1JQzxJSObvcQ?gz<~^#y0gFd$YP9j{LCEdOcC+lDva#$CZ^-!8aOU2zkw zAl7P}(KHYO4;1R9-)>Ll{t*(up&p1zZwpq-xFRhm&s`q+HefNuB6(x9CqH z(O;sXzlmq$78%7{6~{(JCb@RRQwf@M+$~fD@tl)fm7v+eZK5J1Zxc?qX>JS7sRK05 z;2w5pi|h`rjbwhI%+KkWpIby=bY^}j2P`QE=$T(wG8?1Z0~XP~B|MMr=I@IrcT&fb z-AA*^M~F?Cx!xJI013THEavUI7ejDdiz6^%mvq>ceFc6&A^Z*mg@<$*vSl}GQ_koK zR*#NeJy$(6c)I$;m8Ho`6?drBzf#XUQvAwcrS^%1nq&P7UwL(P#~yNb7lU~2{Lq!r zQ`N(x1Ej6-hWn&j)Vix;y9-vGe#TbP%4#`1>2$X~V(lwG)^ z0n@!v6Nq5Zvyuq?1|k_8{d_!y@kHrJd76{|HbQ@(;Pw>qa+eJSR&VSPVEluK`}!7H zr-lx{c#tK{dpkYnY#7kce|y7aZlVio?M2oim(5 zpcYcac8wAgAgA4?wmCpiv=wi)*3<(bHCq$p{?ina!rEfHQ&Z%yX`EWMOIvJTsC9u} z=+vkkj$*Y03gtrlywI>V)`8_zN7}b(_#~WHo)4a`@qXlb_@mfj7;XB z?j*}?t$jPIQ2pu`ybm0I09jCHfQ8P2Q0v}oK<>;stC={;5g#AS<-t`lqIWQrTVhMA zt}ND+7wtacPPJqxP!rL$mh*CF@)7EjPyy^1C+4-^JH)xKd)r7R$oEA_c)qK>V6+T@ z#f8=Tj{-4KqGDqiQ0l49{G=J2KBhaNz|9r!+H80X-vMbbP1pt$Vw<`6vjGKD{*UE$Cxy zdS-q2h_?m|7r?Q8;8@k~;v8db1dbhSU^tfDd0hAKS@XkN9t>s{hcmCtI=h5GAuc=b zobC3pfdyA=!1L!Z&kyrckC@&KE#Nae-#Ey*FZe(-6GrT!L|<^Cz2J1oD33riu16Wp z9G}&{gy9b!Q?T0O$FeW?;A@qANyoV_LkIf8mWSV^A07>)o$DddbxM!Mt?eip;SfXq zWWyOzM#tdopc$m=l-&K4&5cMtca$mP(K%6HVoH;XFE)S1Coa!E)Gc z89B;M2gHwZkc$8i54Bq+JAC-^K(rrTi#qYmEoC<&`d$?3)Tet%Y1L&hl=zq_Awf#J zIkXM+B%v;;4Ds8;vxPQXt{ayV^HkiVujVmz#`1zoHYQr_jC=$|L@l`VV7P;b)BUKX z8`DkxC%lX@hHi$)PWF2kealzSJ2Cp?=L|Y#K``?HVv4p`FnS-x5c4v)q0TTtlhX3{ z%@{p$4ql=yl=Ws;j$rhIUqRO~wNFDAB; z;H1HpI(V~RTBcupOjS8I36(-s`lZ5fk=;D<06O^E6o2*^nGQdXNg54z>4|A0wvWva z^K+aRWJU~kLXysJ_dX+hy-Tn7-vlEG79B`QT3J4T^bDvEDk@@PVlf*};QKhi`HV2a z%Ss}&93(M=vx?a}@eGrIY4}IFEXlHT^PO0G#(Ss|LS_%;c5t!Z4nFu7!g0-A*wEVI zapU8Bu275OueXnKOg8 zwOgo@kuLp#+mGMOwzm-6DkA z-9{v|U~Hvq2?Q{wX7SsJabd(1i~w&c*yLhU|a0D+~qJ2|EVuSH!`6RB2 z+&zHNd#89h?9=F;j**Bbrb_hwWaq%t%zLx^DlQdeKzGy7_IxQW%)X7^CVN|H_R_DX z7sQvsv+O?usz^K!(<+{lf>jlVa24V`P^;U3RNN&3F34RdX%;i%nFVSrR&)H?&WS0yR^8RlRNBk*CJ3jZv~XzsF&H4tJ88s)&)QFjAl1nWriKt4!f3ReeY z>ym7F-LQ}&oQT)?R|_U4lGV>pb5mY#u(8XI=-zML%8^GG9mn{=!`EL<;_84&%k57Xn&Y#m=T-k z6m}vDc4^O00cXLO1(=>z|4RK!rOhiMM=X*is2V-T{A^z;* z_};jmv#1OBzhy50?e#$out>uChX40*NXZewcggqSYKN7KT_I+0!Y{xq3#ZaKNT(Ap z=M7j>6X$sp2E06k(9bw0%|!0ckwV$gDOMN;`MYQ7It7Z{#hv0J!y2JD*WNLBoLs!C zGkwN2TAXEAvr(Mu=(y9WmI4VKsSmB8lV%Nu5Y6In`6xvooF$XbAeDK!S8QsQc{XBk z*hhC-LM+#8lJdUC=hs`*EY|Fvhv`rX2Knyer(DG#BVbwjNEX@xbm6Wjq3Mp~p9&9- z$h|X<#;$^#pd!5mc{AAEL44N2{U3#W0mm!h4^dPFf6#o;QTT(o0qHOjJm(=(0pZ^u zG(fnWh0rnx6ZsHj@Nswm{xNe6LeE1S3?WlbPCSOgM7$K@xGnswhkruxZi0BC>_ZSw z;3Vo#gph^Ab3u~@+VB7+LM$D4kmdp$?`Me+!}+i~mIGW2@I;t^>!EMh3WBe~@r5P> zhkDjS8uu#^Cg9Zo=K?$tCg5hM2Uw15@%#k5Hl9v|33y{1o(L0g55VyVCPD@d^mhV0 z4d96|0sj%ev7Vj?6Yy%F2lG4#`7I)bkp^aeotGqMkPZ zj_FB+3H*})1JeUagcuG<=1Ir^4uL!*hJnKI>3=MO7@m-mM2O`a!xJ)-2$SOQg#08z zOf$y603qg2B23Vekg-IF#~R~bg%H?16(;Zjgzkp{ei=eMr*OO9=#!qv{92dvc;?r6 zq$kRK)ge7m=s=o|k0(6Jr|k99?nb`p7NPJPuMuLJWu42( z+|$6_5?KA+6a#hGHWfOYaAgE7Iz2HeT0G70F+wv0_0Gm+PLJMbhB(|T;J17Gt+hED z9f`WYyusAXAV31LYNl>V8XCa)K4JKnYI>`+zSY^_Y=FucSWAPot*}m|jNMwn0XhB3}zp{_zD@pL?{#^+e?3nPmm?pGB^1fAX*3?6+Y1lYf!>KeQJ8YV4`Ees6oX z&6GrYLAioXlXzPs5EoqN1Tq#MqKQX<9m1AufnDb%9ix|kKbT;eKiKB;5c^v0pX48- z(%RIN#$K#}3nIJHu2vRVZAwa0?4;C6jdfx1*ZIeM{cb)TI(;+$r@BR;+5DYUyIC-s zpH$RtmO!cqJOU)?pbRrh38SckCjiNb2=qlp%P^&RT@{IvBZA0d8kJzr`@_`Yhg6YC z>Wm=rR=JAP(Z!jYKa;ukRKBQs;zhW>ocFc2pq!td>U{V&FZ|}2j~+hs$n(RmbroE# zZ|sg7>#O|T(RIx2=$WBYV-ri0;Q;VI{VsDOuoCVv%i;LIoTnMPYbJjM=I{Z;9efGG ze?W%6`o*XHrmxo5e|gIIBY`td{6o~H=DJPs=r0cbOb|l(zLjYj#MU`jv>J$l>!N=X z3%)C)1p|l>#ILWI+aS2=fNc@3YE-dHoly$a(%c{O2@@M`L;_xEcX$^UHnWQoui!*b zpe}};X_P!fWFJcHN@mfOVj2#5F?*ek{1w&%zQE?N5VqWbDTY9fo7u;3_Klm_9Yhd} zcf0_BID^bN@;;6QvzB?nBtjs)|DdfV1!b~ku@N0^$CY9G3OQ1+g9d4 z495n?#Dao`7^QFRakZPzg!e@`NAJq-PSJo$We!M)|U^8a*-nes^d KdMSr)qyGbi+HpVt literal 0 HcmV?d00001 diff --git a/azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake b/azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake new file mode 100644 index 0000000000..48d174c95a --- /dev/null +++ b/azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake @@ -0,0 +1,12 @@ +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/lib") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug/lib") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/llvm-lto-charset.lib" + DESTINATION "${CURRENT_PACKAGES_DIR}/lib/llvm-lto-charset.lib") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/llvm-lto-charset.lib" + DESTINATION "${CURRENT_PACKAGES_DIR}/lib/debug/llvm-lto-charset.lib") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/include") +file(TOUCH "${CURRENT_PACKAGES_DIR}/include/llvm-lto-lib.h") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share/${PORT}") +file(TOUCH "${CURRENT_PACKAGES_DIR}/share/${PORT}/copyright") diff --git a/azure-pipelines/e2e_ports/llvm-lto-lib/vcpkg.json b/azure-pipelines/e2e_ports/llvm-lto-lib/vcpkg.json new file mode 100644 index 0000000000..eee03841d4 --- /dev/null +++ b/azure-pipelines/e2e_ports/llvm-lto-lib/vcpkg.json @@ -0,0 +1,5 @@ +{ + "name": "llvm-lto-lib", + "version": "1", + "supports": "windows" +} diff --git a/azure-pipelines/end-to-end-tests-dir/regression-ports.ps1 b/azure-pipelines/end-to-end-tests-dir/regression-ports.ps1 new file mode 100644 index 0000000000..c0873c45ed --- /dev/null +++ b/azure-pipelines/end-to-end-tests-dir/regression-ports.ps1 @@ -0,0 +1,6 @@ +. $PSScriptRoot/../end-to-end-tests-prelude.ps1 + +if ($IsWindows) { + Run-Vcpkg install --overlay-ports="$PSScriptRoot/../e2e_ports/llvm-lto-lib" llvm-lto-lib + Throw-IfFailed +} diff --git a/include/vcpkg/base/messages.h b/include/vcpkg/base/messages.h index 4a14a08d8b..ef2ab8221e 100644 --- a/include/vcpkg/base/messages.h +++ b/include/vcpkg/base/messages.h @@ -2119,7 +2119,7 @@ namespace vcpkg "", "The /lib/cmake folder should be merged with /debug/lib/cmake and moved to /share/{spec}/cmake. " "Please use the helper function `vcpkg_cmake_config_fixup()` from the port vcpkg-cmake-config.`"); - DECLARE_MESSAGE(PortBugMismatchedNumberOfBinaries, (), "", "Mismatching number of debug and release binaries."); + DECLARE_MESSAGE(PortBugMismatchedNumberOfBinaries, (), "", "Mismatched number of debug and release binaries."); DECLARE_MESSAGE( PortBugMisplacedCMakeFiles, (msg::spec), diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index 725620914b..7a0be5f244 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -638,19 +638,26 @@ namespace vcpkg } msg::println_warning(msgPortBugMismatchedNumberOfBinaries); - msg::println_warning(msgPortBugFoundDebugBinaries, msg::count = debug_count); - print_paths(debug_binaries); - msg::println_warning(msgPortBugFoundDebugBinaries, msg::count = release_count); - print_paths(release_binaries); - if (debug_count == 0) { - msg::println_warning(msgPortBugMissingDebugBinaries); + msg::println(msgPortBugMissingDebugBinaries); } + else + { + msg::println(msgPortBugFoundDebugBinaries, msg::count = debug_count); + print_paths(debug_binaries); + } + if (release_count == 0) { - msg::println_warning(msgPortBugMissingReleaseBinaries); + msg::println(msgPortBugMissingReleaseBinaries); } + else + { + msg::println(msgPortBugFoundReleaseBinaries, msg::count = release_count); + print_paths(release_binaries); + } + return LintStatus::PROBLEM_DETECTED; } From 0801227bb5a53fe69c649ffefb86c6673b7fda58 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 9 Jan 2023 15:42:47 -0800 Subject: [PATCH 14/33] Whoops dupe directory :) --- azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake b/azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake index 48d174c95a..e4a23521dd 100644 --- a/azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake +++ b/azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake @@ -2,9 +2,9 @@ file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/lib") file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug") file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug/lib") file(COPY "${CMAKE_CURRENT_LIST_DIR}/llvm-lto-charset.lib" - DESTINATION "${CURRENT_PACKAGES_DIR}/lib/llvm-lto-charset.lib") + DESTINATION "${CURRENT_PACKAGES_DIR}/lib") file(COPY "${CMAKE_CURRENT_LIST_DIR}/llvm-lto-charset.lib" - DESTINATION "${CURRENT_PACKAGES_DIR}/lib/debug/llvm-lto-charset.lib") + DESTINATION "${CURRENT_PACKAGES_DIR}/lib/debug") file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/include") file(TOUCH "${CURRENT_PACKAGES_DIR}/include/llvm-lto-lib.h") file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share") From d77dd705fc872bcb225607ce421abbc6edb97bfd Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 9 Jan 2023 18:17:53 -0800 Subject: [PATCH 15/33] Add handling of LLVM bitcode libraries produced by -flto. --- .../e2e_ports/llvm-lto-lib/portfile.cmake | 2 +- .../end-to-end-tests-dir/regression-ports.ps1 | 2 +- include/vcpkg/base/cofffilereader.h | 89 ++++++++++----- include/vcpkg/base/messages.h | 5 - locales/messages.json | 4 +- src/vcpkg/base/cofffilereader.cpp | 101 +++++++----------- src/vcpkg/base/messages.cpp | 1 - src/vcpkg/postbuildlint.cpp | 61 ++++++++--- 8 files changed, 145 insertions(+), 120 deletions(-) diff --git a/azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake b/azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake index e4a23521dd..65cdf3ab9b 100644 --- a/azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake +++ b/azure-pipelines/e2e_ports/llvm-lto-lib/portfile.cmake @@ -4,7 +4,7 @@ file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug/lib") file(COPY "${CMAKE_CURRENT_LIST_DIR}/llvm-lto-charset.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/lib") file(COPY "${CMAKE_CURRENT_LIST_DIR}/llvm-lto-charset.lib" - DESTINATION "${CURRENT_PACKAGES_DIR}/lib/debug") + DESTINATION "${CURRENT_PACKAGES_DIR}/debug/lib") file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/include") file(TOUCH "${CURRENT_PACKAGES_DIR}/include/llvm-lto-lib.h") file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share") diff --git a/azure-pipelines/end-to-end-tests-dir/regression-ports.ps1 b/azure-pipelines/end-to-end-tests-dir/regression-ports.ps1 index c0873c45ed..be08472c18 100644 --- a/azure-pipelines/end-to-end-tests-dir/regression-ports.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/regression-ports.ps1 @@ -1,6 +1,6 @@ . $PSScriptRoot/../end-to-end-tests-prelude.ps1 if ($IsWindows) { - Run-Vcpkg install --overlay-ports="$PSScriptRoot/../e2e_ports/llvm-lto-lib" llvm-lto-lib + Run-Vcpkg install --overlay-ports="$PSScriptRoot/../e2e_ports/llvm-lto-lib" llvm-lto-lib:x64-windows-static Throw-IfFailed } diff --git a/include/vcpkg/base/cofffilereader.h b/include/vcpkg/base/cofffilereader.h index 31b0862df1..61d9d08154 100644 --- a/include/vcpkg/base/cofffilereader.h +++ b/include/vcpkg/base/cofffilereader.h @@ -25,6 +25,21 @@ namespace vcpkg uint16_t characteristics; }; + struct CoffFileHeaderSignature + { + uint16_t machine; + uint16_t number_of_sections; + }; + + struct CoffFileHeaderAfterSignature + { + uint32_t date_time_stamp; + uint32_t pointer_to_symbol_table; + uint32_t number_of_symbols; + uint16_t size_of_optional_header; + uint16_t characteristics; + }; + struct CommonPEOptionalHeaders { uint16_t magic; @@ -276,39 +291,39 @@ namespace vcpkg uint64_t CHPEMetadataPointer; }; + // It is expected that enumerators not in this list may be present. enum class MachineType : uint16_t { - UNKNOWN = 0x0, // The contents of this field are assumed to be applicable to any machine type - AM33 = 0x1d3, // Matsushita AM33 - AMD64 = 0x8664, // x64 - ARM = 0x1c0, // ARM little endian - ARM64 = 0xaa64, // ARM64 little endian - ARM64EC = 0xa641, // ARM64 "emulation compatible" - ARM64X = 0xa64e, // ARM64X - ARMNT = 0x1c4, // ARM Thumb-2 little endian - EBC = 0xebc, // EFI byte code - I386 = 0x14c, // Intel 386 or later processors and compatible processors - IA64 = 0x200, // Intel Itanium processor family - M32R = 0x9041, // Mitsubishi M32R little endian - MIPS16 = 0x266, // MIPS16 - MIPSFPU = 0x366, // MIPS with FPU - MIPSFPU16 = 0x466, // MIPS16 with FPU - POWERPC = 0x1f0, // Power PC little endian - POWERPCFP = 0x1f1, // Power PC with floating point support - R4000 = 0x166, // MIPS little endian - RISCV32 = 0x5032, // RISC-V 32-bit address space - RISCV64 = 0x5064, // RISC-V 64-bit address space - RISCV128 = 0x5128, // RISC-V 128-bit address space - SH3 = 0x1a2, // Hitachi SH3 - SH3DSP = 0x1a3, // Hitachi SH3 DSP - SH4 = 0x1a6, // Hitachi SH4 - SH5 = 0x1a8, // Hitachi SH5 - THUMB = 0x1c2, // Thumb - WCEMIPSV2 = 0x169, // MIPS little-endian WCE v2 + UNKNOWN = 0x0, // The contents of this field are assumed to be applicable to any machine type + AM33 = 0x1d3, // Matsushita AM33 + AMD64 = 0x8664, // x64 + ARM = 0x1c0, // ARM little endian + ARM64 = 0xaa64, // ARM64 little endian + ARM64EC = 0xa641, // ARM64 "emulation compatible" + ARM64X = 0xa64e, // ARM64X + ARMNT = 0x1c4, // ARM Thumb-2 little endian + EBC = 0xebc, // EFI byte code + I386 = 0x14c, // Intel 386 or later processors and compatible processors + IA64 = 0x200, // Intel Itanium processor family + M32R = 0x9041, // Mitsubishi M32R little endian + MIPS16 = 0x266, // MIPS16 + MIPSFPU = 0x366, // MIPS with FPU + MIPSFPU16 = 0x466, // MIPS16 with FPU + POWERPC = 0x1f0, // Power PC little endian + POWERPCFP = 0x1f1, // Power PC with floating point support + R4000 = 0x166, // MIPS little endian + RISCV32 = 0x5032, // RISC-V 32-bit address space + RISCV64 = 0x5064, // RISC-V 64-bit address space + RISCV128 = 0x5128, // RISC-V 128-bit address space + SH3 = 0x1a2, // Hitachi SH3 + SH3DSP = 0x1a3, // Hitachi SH3 DSP + SH4 = 0x1a6, // Hitachi SH4 + SH5 = 0x1a8, // Hitachi SH5 + THUMB = 0x1c2, // Thumb + WCEMIPSV2 = 0x169, // MIPS little-endian WCE v2 + LLVM_BITCODE = 0x4342, // LLVM bitcode https://www.llvm.org/docs/BitCodeFormat.html#llvm-ir-magic-number }; - MachineType to_machine_type(const uint16_t value); - enum class PEType { Unset, @@ -377,6 +392,22 @@ namespace vcpkg // 11 bits: reserved and must be 0 }; + constexpr uint32_t ImportHeaderSignature = 0xFFFF0000u; + constexpr uint32_t LlvmBitcodeSignature = 0xDEC04342u; + + struct ImportHeaderAfterSignature + { + uint16_t version; + uint16_t machine; + uint32_t date_time_stamp; + uint32_t size_of_data; + uint16_t ordinal_hint; + uint16_t type_and_name_type; + // 2 bits: type + // 3 bits: name type + // 11 bits: reserved and must be 0 + }; + struct LibInformation { std::vector machine_types; diff --git a/include/vcpkg/base/messages.h b/include/vcpkg/base/messages.h index ef2ab8221e..206202f259 100644 --- a/include/vcpkg/base/messages.h +++ b/include/vcpkg/base/messages.h @@ -2383,11 +2383,6 @@ namespace vcpkg "unknown binary provider type: valid providers are 'clear', 'default', 'nuget', " "'nugetconfig','nugettimeout', 'interactive', 'x-azblob', 'x-gcs', 'x-aws', " "'x-aws-config', 'http', and 'files'"); - DECLARE_MESSAGE(UnknownMachineCode, - (msg::value), - "{value} is machine type code, see " - "https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types", - "Unknown machine type code {value}"); DECLARE_MESSAGE(UnknownOptions, (msg::command_name), "", "Unknown option(s) for command '{command_name}':"); DECLARE_MESSAGE(UnknownParameterForIntegrate, (msg::value), diff --git a/locales/messages.json b/locales/messages.json index f501d83615..2d9c09a2f1 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -939,7 +939,7 @@ "_PortBugInvalidCrtLinkageEntry.comment": "See explanation in PortBugInvalidCrtLinkage An example of {path} is /foo/bar.", "PortBugMergeLibCMakeDir": "The /lib/cmake folder should be merged with /debug/lib/cmake and moved to /share/{spec}/cmake. Please use the helper function `vcpkg_cmake_config_fixup()` from the port vcpkg-cmake-config.`", "_PortBugMergeLibCMakeDir.comment": "An example of {spec} is zlib:x64-windows.", - "PortBugMismatchedNumberOfBinaries": "Mismatching number of debug and release binaries.", + "PortBugMismatchedNumberOfBinaries": "Mismatched number of debug and release binaries.", "PortBugMisplacedCMakeFiles": "The following cmake files were found outside /share/{spec}. Please place cmake files in /share/{spec}.", "_PortBugMisplacedCMakeFiles.comment": "An example of {spec} is zlib:x64-windows.", "PortBugMisplacedFiles": "The following files are placed in {path}:", @@ -1094,8 +1094,6 @@ "_UnexpectedToolOutput.comment": "The actual command line output will be appended after this message. An example of {tool_name} is aria2. An example of {path} is /foo/bar.", "UnknownBaselineFileContent": "unrecognizable baseline entry; expected 'port:triplet=(fail|skip|pass)'", "UnknownBinaryProviderType": "unknown binary provider type: valid providers are 'clear', 'default', 'nuget', 'nugetconfig','nugettimeout', 'interactive', 'x-azblob', 'x-gcs', 'x-aws', 'x-aws-config', 'http', and 'files'", - "UnknownMachineCode": "Unknown machine type code {value}", - "_UnknownMachineCode.comment": "{value} is machine type code, see https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types", "UnknownOptions": "Unknown option(s) for command '{command_name}':", "_UnknownOptions.comment": "An example of {command_name} is install.", "UnknownParameterForIntegrate": "Unknown parameter '{value}' for integrate.", diff --git a/src/vcpkg/base/cofffilereader.cpp b/src/vcpkg/base/cofffilereader.cpp index 5d6dbe19e0..eada1bf559 100644 --- a/src/vcpkg/base/cofffilereader.cpp +++ b/src/vcpkg/base/cofffilereader.cpp @@ -380,6 +380,17 @@ namespace return offsets; } + static void add_machine_type(std::vector& machine_types, MachineType machine_type) + { + if (machine_type == MachineType::UNKNOWN || + std::find(machine_types.begin(), machine_types.end(), machine_type) != machine_types.end()) + { + return; + } + + machine_types.push_back(machine_type); + } + LibInformation read_lib_information_from_archive_members(const vcpkg::ReadFilePointer& f, const std::vector& member_offsets) { @@ -391,36 +402,40 @@ namespace // Skip the header, no need to read it const auto coff_base = offset + sizeof(ArchiveMemberHeader); Checks::check_exit(VCPKG_LINE_INFO, f.seek(coff_base, SEEK_SET) == 0); - static_assert(sizeof(CoffFileHeader) == sizeof(ImportHeader), "Boom"); - char loaded_header[sizeof(CoffFileHeader)]; - Checks::check_exit(VCPKG_LINE_INFO, f.read(&loaded_header, sizeof(loaded_header), 1) == 1); - - CoffFileHeader coff_header; - ::memcpy(&coff_header, loaded_header, sizeof(coff_header)); - auto result_machine_type = to_machine_type(coff_header.machine); - bool import_object = false; - if (result_machine_type == MachineType::UNKNOWN) + uint32_t tag_sniffer; + Checks::check_exit(VCPKG_LINE_INFO, f.read(&tag_sniffer, sizeof(tag_sniffer), 1) == 1); + if (tag_sniffer == LlvmBitcodeSignature) { - ImportHeader import_header; - ::memcpy(&import_header, loaded_header, sizeof(import_header)); - if (import_header.sig2 == 0xFFFFu) - { - import_object = true; - result_machine_type = to_machine_type(import_header.machine); - } + // obj is LLVM bitcode + add_machine_type(machine_types, MachineType::LLVM_BITCODE); } - - if (!import_object) + else if (tag_sniffer == ImportHeaderSignature) + { + // obj is an import obj + ImportHeaderAfterSignature import_header; + Checks::check_exit(VCPKG_LINE_INFO, f.read(&import_header, sizeof(import_header), 1) == 1); + add_machine_type(machine_types, static_cast(import_header.machine)); + } + else { + // obj is traditional COFF + CoffFileHeaderSignature coff_signature; + static_assert(sizeof(tag_sniffer) == sizeof(coff_signature), "BOOM"); + memcpy(&coff_signature, &tag_sniffer, sizeof(tag_sniffer)); + add_machine_type(machine_types, static_cast(coff_signature.machine)); + + CoffFileHeaderAfterSignature coff_header; + Checks::check_exit(VCPKG_LINE_INFO, f.read(&coff_header, sizeof(coff_header), 1) == 1); + // Object files shouldn't have optional headers, but the spec says we should skip over one if any f.seek(coff_header.size_of_optional_header, SEEK_CUR); // Read section headers std::vector sections; - sections.resize(coff_header.number_of_sections); + sections.resize(coff_signature.number_of_sections); Checks::check_exit(VCPKG_LINE_INFO, f.read(sections.data(), sizeof(SectionTableHeader), - coff_header.number_of_sections) == coff_header.number_of_sections); + coff_signature.number_of_sections) == coff_signature.number_of_sections); // Look for linker directive sections for (auto&& section : sections) { @@ -456,14 +471,6 @@ namespace } } } - - if (result_machine_type == MachineType::UNKNOWN || - std::find(machine_types.begin(), machine_types.end(), result_machine_type) != machine_types.end()) - { - continue; - } - - machine_types.push_back(result_machine_type); } std::sort(machine_types.begin(), machine_types.end()); @@ -484,7 +491,7 @@ namespace vcpkg } } - MachineType DllMetadata::get_machine_type() const noexcept { return to_machine_type(coff_header.machine); } + MachineType DllMetadata::get_machine_type() const noexcept { return static_cast(coff_header.machine); } void ArchiveMemberHeader::check_end_of_header() const { @@ -755,40 +762,4 @@ namespace vcpkg return read_lib_information_from_archive_members(f, *offsets); } - - MachineType to_machine_type(const uint16_t value) - { - const MachineType t = static_cast(value); - switch (t) - { - case MachineType::UNKNOWN: - case MachineType::AM33: - case MachineType::AMD64: - case MachineType::ARM: - case MachineType::ARM64: - case MachineType::ARM64EC: - case MachineType::ARM64X: - case MachineType::ARMNT: - case MachineType::EBC: - case MachineType::I386: - case MachineType::IA64: - case MachineType::M32R: - case MachineType::MIPS16: - case MachineType::MIPSFPU: - case MachineType::MIPSFPU16: - case MachineType::POWERPC: - case MachineType::POWERPCFP: - case MachineType::R4000: - case MachineType::RISCV32: - case MachineType::RISCV64: - case MachineType::RISCV128: - case MachineType::SH3: - case MachineType::SH3DSP: - case MachineType::SH4: - case MachineType::SH5: - case MachineType::THUMB: - case MachineType::WCEMIPSV2: return t; - default: Checks::msg_exit_maybe_upgrade(VCPKG_LINE_INFO, msgUnknownMachineCode, msg::value = value); - } - } } diff --git a/src/vcpkg/base/messages.cpp b/src/vcpkg/base/messages.cpp index b8cab3227f..cdbed1ae2c 100644 --- a/src/vcpkg/base/messages.cpp +++ b/src/vcpkg/base/messages.cpp @@ -956,7 +956,6 @@ namespace vcpkg REGISTER_MESSAGE(UnexpectedToolOutput); REGISTER_MESSAGE(UnknownBaselineFileContent); REGISTER_MESSAGE(UnknownBinaryProviderType); - REGISTER_MESSAGE(UnknownMachineCode); REGISTER_MESSAGE(UnknownOptions); REGISTER_MESSAGE(UnknownParameterForIntegrate); REGISTER_MESSAGE(UnknownPolicySetting); diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index 7a0be5f244..8bafa53b2d 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -496,18 +496,39 @@ namespace vcpkg std::string actual_arch; }; - static std::string get_actual_architecture(const MachineType& machine_type) + static std::string get_printable_architecture(const MachineType& machine_type) { switch (machine_type) { - case MachineType::AMD64: - case MachineType::IA64: return "x64"; - case MachineType::I386: return "x86"; - case MachineType::ARM: - case MachineType::ARMNT: return "arm"; + case MachineType::UNKNOWN: return "unknown"; + case MachineType::AM33: return "matsushita-am33"; + case MachineType::AMD64: return "x64"; + case MachineType::ARM: return "arm"; case MachineType::ARM64: return "arm64"; case MachineType::ARM64EC: return "arm64ec"; - default: return "Machine Type Code = " + std::to_string(static_cast(machine_type)); + case MachineType::ARM64X: return "arm64x"; + case MachineType::ARMNT: return "arm"; + case MachineType::EBC: return "efi-byte-code"; + case MachineType::I386: return "x86"; + case MachineType::IA64: return "ia64"; + case MachineType::M32R: return "mitsubishi-m32r-le"; + case MachineType::MIPS16: return "mips16"; + case MachineType::MIPSFPU: return "mipsfpu"; + case MachineType::MIPSFPU16: return "mipsfpu16"; + case MachineType::POWERPC: return "ppc"; + case MachineType::POWERPCFP: return "ppcfp"; + case MachineType::R4000: return "mips-le"; + case MachineType::RISCV32: return "riscv-32"; + case MachineType::RISCV64: return "riscv-64"; + case MachineType::RISCV128: return "riscv-128"; + case MachineType::SH3: return "hitachi-sh3"; + case MachineType::SH3DSP: return "hitachi-sh3-dsp"; + case MachineType::SH4: return "hitachi-sh4"; + case MachineType::SH5: return "hitachi-sh5"; + case MachineType::THUMB: return "thumb"; + case MachineType::WCEMIPSV2: return "mips-le-wce-v2"; + case MachineType::LLVM_BITCODE: return "llvm-bitcode"; + default: return "unknown-" + std::to_string(static_cast(machine_type)); } } @@ -531,10 +552,10 @@ namespace vcpkg for (const PostBuildCheckDllData& dll_data : dlls) { - const std::string actual_architecture = get_actual_architecture(dll_data.machine_type); + const std::string actual_architecture = get_printable_architecture(dll_data.machine_type); if (expected_architecture == "arm64ec") { - if (actual_architecture != "x64" || !dll_data.is_arm64_ec) + if (dll_data.machine_type != MachineType::AMD64 || !dll_data.is_arm64_ec) { binaries_with_invalid_architecture.push_back({dll_data.path, actual_architecture}); } @@ -570,16 +591,26 @@ namespace vcpkg msg::extension = ".lib", msg::path = file); - const auto machine_types = - Util::fmap(read_lib_information(fs.open_for_read(file, VCPKG_LINE_INFO)).machine_types, - [](MachineType mt) { return get_actual_architecture(mt); }); + auto machine_types = read_lib_information(fs.open_for_read(file, VCPKG_LINE_INFO)).machine_types; + { + auto llvm_bitcode = + std::find(machine_types.begin(), machine_types.end(), MachineType::LLVM_BITCODE); + if (llvm_bitcode != machine_types.end()) + { + machine_types.erase(llvm_bitcode); + } + } + + auto printable_machine_types = + Util::fmap(machine_types, [](MachineType mt) { return get_printable_architecture(mt); }); // Either machine_types is empty (meaning this lib is architecture independent), or // we need at least one of the machine types to match. - // Agnostic example: Folly's debug library + // Agnostic example: Folly's debug library, LLVM LTO libraries // Multiple example: arm64x libraries - if (!machine_types.empty() && !Util::Vectors::contains(machine_types, expected_architecture)) + if (!printable_machine_types.empty() && + !Util::Vectors::contains(printable_machine_types, expected_architecture)) { - binaries_with_invalid_architecture.push_back({file, Strings::join(",", machine_types)}); + binaries_with_invalid_architecture.push_back({file, Strings::join(",", printable_machine_types)}); } } } From ef49056bf53bab4ff9c996145ed18cc1f3365eed Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 10 Jan 2023 12:46:01 -0800 Subject: [PATCH 16/33] Don't try to give non-Windows libs to Windows post build checks. --- src/vcpkg/postbuildlint.cpp | 122 +++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 58 deletions(-) diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index 8bafa53b2d..e928049ecf 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -1141,7 +1141,8 @@ namespace vcpkg const auto release_bin_dir = package_dir / "bin"; NotExtensionsCaseInsensitive lib_filter; - if (Util::Vectors::contains(windows_system_names, pre_build_info.cmake_system_name)) + const bool windows_target = Util::Vectors::contains(windows_system_names, pre_build_info.cmake_system_name); + if (windows_target) { lib_filter = NotExtensionsCaseInsensitive{{".lib"}}; } @@ -1160,78 +1161,83 @@ namespace vcpkg error_count += check_matching_debug_and_release_binaries(debug_libs, release_libs); } - if (!build_info.policies.is_enabled(BuildPolicy::SKIP_ARCHITECTURE_CHECK)) + if (windows_target) { - std::vector 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, pre_build_info.cmake_system_name, libs, fs); - } + Debug::println("Running windows targeting post-build checks"); + if (!build_info.policies.is_enabled(BuildPolicy::SKIP_ARCHITECTURE_CHECK)) + { + std::vector 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, pre_build_info.cmake_system_name, libs, fs); + } - std::vector debug_dlls = fs.get_regular_files_recursive(debug_bin_dir, IgnoreErrors{}); - Util::erase_remove_if(debug_dlls, NotExtensionCaseInsensitive{".dll"}); - std::vector release_dlls = fs.get_regular_files_recursive(release_bin_dir, IgnoreErrors{}); - Util::erase_remove_if(release_dlls, NotExtensionCaseInsensitive{".dll"}); + std::vector debug_dlls = fs.get_regular_files_recursive(debug_bin_dir, IgnoreErrors{}); + Util::erase_remove_if(debug_dlls, NotExtensionCaseInsensitive{".dll"}); + std::vector release_dlls = fs.get_regular_files_recursive(release_bin_dir, IgnoreErrors{}); + Util::erase_remove_if(release_dlls, NotExtensionCaseInsensitive{".dll"}); - switch (build_info.library_linkage) - { - case LinkageType::DYNAMIC: + switch (build_info.library_linkage) { - 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_dlls, release_dlls); - - error_count += check_lib_files_are_available_if_dlls_are_available( - build_info.policies, debug_libs.size(), debug_dlls.size(), debug_lib_dir); - error_count += check_lib_files_are_available_if_dlls_are_available( - build_info.policies, release_libs.size(), release_dlls.size(), release_lib_dir); - - std::vector dlls; - dlls.reserve(debug_dlls.size() + release_dlls.size()); - for (const Path& dll : debug_dlls) + case LinkageType::DYNAMIC: { - auto maybe_dll_data = try_load_dll_data(fs, dll); - if (const auto dll_data = maybe_dll_data.get()) + 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_dlls, release_dlls); + + error_count += check_lib_files_are_available_if_dlls_are_available( + build_info.policies, debug_libs.size(), debug_dlls.size(), debug_lib_dir); + error_count += check_lib_files_are_available_if_dlls_are_available( + build_info.policies, release_libs.size(), release_dlls.size(), release_lib_dir); + + std::vector dlls; + dlls.reserve(debug_dlls.size() + release_dlls.size()); + for (const Path& dll : debug_dlls) { - dlls.emplace_back(std::move(*dll_data)); + auto maybe_dll_data = try_load_dll_data(fs, dll); + if (const auto dll_data = maybe_dll_data.get()) + { + dlls.emplace_back(std::move(*dll_data)); + } } - } - for (const Path& dll : release_dlls) - { - auto maybe_dll_data = try_load_dll_data(fs, dll); - if (const auto dll_data = maybe_dll_data.get()) + for (const Path& dll : release_dlls) { - dlls.emplace_back(std::move(*dll_data)); + auto maybe_dll_data = try_load_dll_data(fs, dll); + if (const auto dll_data = maybe_dll_data.get()) + { + dlls.emplace_back(std::move(*dll_data)); + } } - } - error_count += check_exports_of_dlls(build_info.policies, dlls); - error_count += check_uwp_bit_of_dlls(pre_build_info.cmake_system_name, dlls); - error_count += check_outdated_crt_linkage_of_dlls(dlls, build_info, pre_build_info); - if (!build_info.policies.is_enabled(BuildPolicy::SKIP_ARCHITECTURE_CHECK)) - { - error_count += check_dll_architecture(pre_build_info.target_architecture, dlls); + error_count += check_exports_of_dlls(build_info.policies, dlls); + error_count += check_uwp_bit_of_dlls(pre_build_info.cmake_system_name, dlls); + error_count += check_outdated_crt_linkage_of_dlls(dlls, build_info, pre_build_info); + if (!build_info.policies.is_enabled(BuildPolicy::SKIP_ARCHITECTURE_CHECK)) + { + error_count += check_dll_architecture(pre_build_info.target_architecture, dlls); + } } - } - break; - case LinkageType::STATIC: - { - auto dlls = release_dlls; - dlls.insert(dlls.end(), debug_dlls.begin(), debug_dlls.end()); - error_count += check_no_dlls_present(build_info.policies, dlls); - - error_count += check_bin_folders_are_not_present_in_static_build(build_info.policies, fs, package_dir); - if (!build_info.policies.is_enabled(BuildPolicy::ONLY_RELEASE_CRT)) + break; + case LinkageType::STATIC: { - error_count += check_crt_linkage_of_libs(fs, build_info, false, debug_libs); - } + auto dlls = release_dlls; + dlls.insert(dlls.end(), debug_dlls.begin(), debug_dlls.end()); + error_count += check_no_dlls_present(build_info.policies, dlls); - error_count += check_crt_linkage_of_libs(fs, build_info, true, release_libs); - break; + error_count += + check_bin_folders_are_not_present_in_static_build(build_info.policies, fs, package_dir); + if (!build_info.policies.is_enabled(BuildPolicy::ONLY_RELEASE_CRT)) + { + error_count += check_crt_linkage_of_libs(fs, build_info, false, debug_libs); + } + + error_count += check_crt_linkage_of_libs(fs, build_info, true, release_libs); + break; + } + default: Checks::unreachable(VCPKG_LINE_INFO); } - default: Checks::unreachable(VCPKG_LINE_INFO); } error_count += check_no_empty_folders(fs, package_dir); From d15b5e6ae13dc57e766b70ab7adfeefd4b78d85d Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 10 Jan 2023 13:33:41 -0800 Subject: [PATCH 17/33] Harden the lib reader. --- include/vcpkg/base/cofffilereader.h | 3 +- include/vcpkg/base/files.h | 2 +- include/vcpkg/base/messages.h | 8 +- locales/messages.json | 4 +- src/vcpkg/base/cofffilereader.cpp | 216 +++++++++++++++++++--------- src/vcpkg/base/files.cpp | 21 ++- src/vcpkg/base/messages.cpp | 4 +- src/vcpkg/postbuildlint.cpp | 6 +- 8 files changed, 176 insertions(+), 88 deletions(-) diff --git a/include/vcpkg/base/cofffilereader.h b/include/vcpkg/base/cofffilereader.h index 61d9d08154..d758d1cd1b 100644 --- a/include/vcpkg/base/cofffilereader.h +++ b/include/vcpkg/base/cofffilereader.h @@ -373,7 +373,6 @@ namespace vcpkg char size[10]; char end_of_header[2]; - void check_end_of_header() const; uint64_t decoded_size() const; }; @@ -418,5 +417,5 @@ namespace vcpkg ExpectedL try_read_dll_metadata(ReadFilePointer& f); ExpectedL try_read_if_dll_has_exports(const DllMetadata& dll, ReadFilePointer& f); ExpectedL> try_read_dll_imported_dll_names(const DllMetadata& dll, ReadFilePointer& f); - LibInformation read_lib_information(const ReadFilePointer& f); + ExpectedL read_lib_information(ReadFilePointer& f); } diff --git a/include/vcpkg/base/files.h b/include/vcpkg/base/files.h index b16215fd2e..950ce31ffb 100644 --- a/include/vcpkg/base/files.h +++ b/include/vcpkg/base/files.h @@ -118,13 +118,13 @@ namespace vcpkg FilePointer& operator=(const FilePointer&) = delete; explicit operator bool() const noexcept; - int seek(long long offset, int origin) const noexcept; long long tell() const noexcept; int eof() const noexcept; std::error_code error() const noexcept; const Path& path() const; ExpectedL try_seek_to(long long offset); + ExpectedL try_seek_to(long long offset, int origin); ~FilePointer(); }; diff --git a/include/vcpkg/base/messages.h b/include/vcpkg/base/messages.h index 206202f259..da9983e647 100644 --- a/include/vcpkg/base/messages.h +++ b/include/vcpkg/base/messages.h @@ -1579,7 +1579,6 @@ namespace vcpkg "{value} is a sha.", "SHA512's must be 128 hex characters: {value}"); DECLARE_MESSAGE(IncorrectArchiveFileSignature, (), "", "Incorrect archive file signature"); - DECLARE_MESSAGE(IncorrectLibHeaderEnd, (), "", "Incorrect lib header end"); DECLARE_MESSAGE(IncorrectNumberOfArgs, (msg::command_name, msg::expected, msg::actual), "'{expected}' is the required number of arguments. '{actual}' is the number of arguments provided.", @@ -1720,6 +1719,8 @@ namespace vcpkg "invalid format string: {actual}"); DECLARE_MESSAGE(InvalidHexDigit, (), "", "Invalid hex digit in unicode escape"); DECLARE_MESSAGE(InvalidIntegerConst, (msg::count), "", "Invalid integer constant: {count}"); + DECLARE_MESSAGE(InvalidLibraryMissingLinkerMembers, (), "", "Library was invalid: could not find a linker member."); + DECLARE_MESSAGE(InvalidLibraryMissingSignature, (), "", "Library was invalid: did not find ! signature."); DECLARE_MESSAGE( InvalidLinkage, (msg::system_name, msg::value), @@ -1746,6 +1747,11 @@ namespace vcpkg (msg::tool_name), "A platform API call failure message is appended after this", "Launching {tool_name}:"); + DECLARE_MESSAGE(LibraryArchiveMemberTooSmall, + (), + "", + "A library archive member was too small to contain the expected data type."); + DECLARE_MESSAGE(LibraryFirstLinkerMemberMissing, (), "", "Could not find first linker member name."); DECLARE_MESSAGE(LicenseExpressionContainsExtraPlus, (), "", diff --git a/locales/messages.json b/locales/messages.json index 2d9c09a2f1..e6fc683912 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -652,7 +652,6 @@ "ImproperShaLength": "SHA512's must be 128 hex characters: {value}", "_ImproperShaLength.comment": "{value} is a sha.", "IncorrectArchiveFileSignature": "Incorrect archive file signature", - "IncorrectLibHeaderEnd": "Incorrect lib header end", "IncorrectNumberOfArgs": "'{command_name}' requires '{expected}' arguments, but '{actual}' were provided.", "_IncorrectNumberOfArgs.comment": "'{expected}' is the required number of arguments. '{actual}' is the number of arguments provided. An example of {command_name} is install.", "IncorrectPESignature": "Incorrect PE signature", @@ -736,6 +735,7 @@ "InvalidHexDigit": "Invalid hex digit in unicode escape", "InvalidIntegerConst": "Invalid integer constant: {count}", "_InvalidIntegerConst.comment": "An example of {count} is 42.", + "InvalidLibraryMissingLinkerMembers": "Library was invalid: could not find a linker member.", "InvalidLinkage": "Invalid {system_name} linkage type: [{value}]", "_InvalidLinkage.comment": "'{value}' is the linkage type vcpkg would did not understand. (Correct values would be static ofr dynamic) An example of {system_name} is Darwin.", "InvalidOptionForRemove": "'remove' accepts either libraries or '--outdated'", @@ -759,6 +759,8 @@ "JsonValueNotString": "json value is not a string", "LaunchingProgramFailed": "Launching {tool_name}:", "_LaunchingProgramFailed.comment": "A platform API call failure message is appended after this An example of {tool_name} is aria2.", + "LibraryArchiveMemberTooSmall": "A library archive member was too small to contain the expected data type.", + "LibraryFirstLinkerMemberMissing": "Could not find first linker member name.", "LicenseExpressionContainsExtraPlus": "SPDX license expression contains an extra '+'. These are only allowed directly after a license identifier.", "LicenseExpressionContainsInvalidCharacter": "SPDX license expression contains an invalid character (0x{value:02X} '{value}').", "_LicenseExpressionContainsInvalidCharacter.comment": "example of {value:02X} is '7B'\nexample of {value} is '{'", diff --git a/src/vcpkg/base/cofffilereader.cpp b/src/vcpkg/base/cofffilereader.cpp index eada1bf559..ee38be9e09 100644 --- a/src/vcpkg/base/cofffilereader.cpp +++ b/src/vcpkg/base/cofffilereader.cpp @@ -256,19 +256,20 @@ namespace static_assert(sizeof(ArchiveMemberHeader) == 60, "The ArchiveMemberHeader struct must match its on-disk representation"); - void read_and_verify_archive_file_signature(const ReadFilePointer& f) + ExpectedL read_and_verify_archive_file_signature(ReadFilePointer& f) { static constexpr StringLiteral FILE_START = "!\n"; - Checks::check_exit(VCPKG_LINE_INFO, f.seek(0, SEEK_SET) == 0); - - char file_start[FILE_START.size()]; - Checks::check_exit(VCPKG_LINE_INFO, f.read(&file_start, FILE_START.size(), 1) == 1); + static constexpr auto FILE_START_SIZE = FILE_START.size(); + return f.try_seek_to(0).then([&f](Unit) -> ExpectedL { + char file_start[FILE_START.size()]; + auto result = f.try_read_all(file_start, FILE_START_SIZE); + if (result.has_value() && FILE_START != StringView{file_start, FILE_START_SIZE}) + { + return msg::format_error(msgIncorrectArchiveFileSignature); + } - if (FILE_START != StringView{file_start, FILE_START.size()}) - { - msg::println_error(msgIncorrectArchiveFileSignature); - Checks::exit_fail(VCPKG_LINE_INFO); - } + return result; + }); } uint32_t bswap(uint32_t value) @@ -276,44 +277,45 @@ namespace return (value >> 24) | ((value & 0x00FF0000u) >> 8) | ((value & 0x0000FF00u) << 8) | (value << 24); } - Optional> try_read_first_linker_member_offsets(const vcpkg::ReadFilePointer& f) + ExpectedL> try_read_first_linker_member_offsets(ReadFilePointer& f) { ArchiveMemberHeader first_linker_member_header; Checks::check_exit(VCPKG_LINE_INFO, f.read(&first_linker_member_header, sizeof(first_linker_member_header), 1) == 1); if (memcmp(first_linker_member_header.name, "/ ", 2) != 0) { - Debug::println("Could not find proper first linker member"); - return nullopt; + return msg::format_error(msgLibraryFirstLinkerMemberMissing); } auto first_size = first_linker_member_header.decoded_size(); uint32_t archive_symbol_count; if (first_size < sizeof(archive_symbol_count)) { - Debug::println("Firstlinker member was too small to contain a single uint32_t"); - return nullopt; + return msg::format_error(msgLibraryArchiveMemberTooSmall); } - if (f.read(&archive_symbol_count, sizeof(archive_symbol_count), 1) != 1) { - Debug::println("Could not read first linker member."); - return nullopt; + auto read = f.try_read_all(&archive_symbol_count, sizeof(archive_symbol_count)); + if (!read.has_value()) + { + return std::move(read).error(); + } } archive_symbol_count = bswap(archive_symbol_count); const auto maximum_possible_archive_members = (first_size / sizeof(uint32_t)) - 1; if (archive_symbol_count > maximum_possible_archive_members) { - Debug::println("First linker member was too small to contain the expected number of symbols"); - return nullopt; + return msg::format_error(msgLibraryArchiveMemberTooSmall); } std::vector offsets(archive_symbol_count); - if (f.read(offsets.data(), sizeof(uint32_t), archive_symbol_count) != archive_symbol_count) { - Debug::println("Could not read first linker member offsets."); - return nullopt; + auto read = f.try_read_all(offsets.data(), sizeof(uint32_t) * archive_symbol_count); + if (!read.has_value()) + { + return std::move(read).error(); + } } // convert (big endian) offsets to little endian @@ -326,18 +328,30 @@ namespace offsets.erase(std::remove(offsets.begin(), offsets.end(), 0u), offsets.end()); std::sort(offsets.begin(), offsets.end()); uint64_t leftover = first_size - sizeof(uint32_t) - (archive_symbol_count * sizeof(uint32_t)); - Checks::check_exit(VCPKG_LINE_INFO, f.seek(leftover, SEEK_CUR) == 0); + { + auto seek = f.try_seek_to(leftover, SEEK_CUR); + if (!seek.has_value()) + { + return std::move(seek).error(); + } + } + return offsets; } - Optional> try_read_second_linker_member_offsets(const vcpkg::ReadFilePointer& f) + ExpectedL>> try_read_second_linker_member_offsets(ReadFilePointer& f) { ArchiveMemberHeader second_linker_member_header; - Checks::check_exit(VCPKG_LINE_INFO, - f.read(&second_linker_member_header, sizeof(second_linker_member_header), 1) == 1); + { + auto read = f.try_read_all(&second_linker_member_header, sizeof(second_linker_member_header)); + if (!read.has_value()) + { + return std::move(read).error(); + } + } + if (memcmp(second_linker_member_header.name, "/ ", 2) != 0) { - Debug::println("Could not find proper second linker member"); return nullopt; } @@ -347,28 +361,30 @@ namespace if (second_size < sizeof(archive_member_count)) { - Debug::println("Second linker member was too small to contain a single uint32_t"); - return nullopt; + return msg::format_error(msgLibraryArchiveMemberTooSmall); } - if (f.read(&archive_member_count, sizeof(archive_member_count), 1) != 1) { - Debug::println("Failed to read second linker member member count."); - return nullopt; + auto read = f.try_read_all(&archive_member_count, sizeof(archive_member_count)); + if (!read.has_value()) + { + return std::move(read).error(); + } } const auto maximum_possible_archive_members = (second_size / sizeof(uint32_t)) - 1; if (archive_member_count > maximum_possible_archive_members) { - Debug::println("Second linker member was too small to contain the expected number of archive members"); - return nullopt; + return msg::format_error(msgLibraryArchiveMemberTooSmall); } std::vector offsets(archive_member_count); - if (f.read(offsets.data(), sizeof(uint32_t), archive_member_count) != archive_member_count) { - Debug::println("Failed to read second linker member offsets"); - return nullopt; + auto read = f.try_read_all(offsets.data(), sizeof(uint32_t) * archive_member_count); + if (!read.has_value()) + { + return std::move(read).error(); + } } // Ignore offsets that point to offset 0. See vcpkg github #223 #288 #292 @@ -376,7 +392,14 @@ namespace // Sort the offsets, because it is possible for them to be unsorted. See vcpkg github #292 std::sort(offsets.begin(), offsets.end()); uint64_t leftover = second_size - sizeof(uint32_t) - (archive_member_count * sizeof(uint32_t)); - Checks::check_exit(VCPKG_LINE_INFO, f.seek(leftover, SEEK_CUR) == 0); + { + auto seek = f.try_seek_to(leftover, SEEK_CUR); + if (!seek.has_value()) + { + return std::move(seek).error(); + } + } + return offsets; } @@ -391,8 +414,8 @@ namespace machine_types.push_back(machine_type); } - LibInformation read_lib_information_from_archive_members(const vcpkg::ReadFilePointer& f, - const std::vector& member_offsets) + ExpectedL read_lib_information_from_archive_members(ReadFilePointer& f, + const std::vector& member_offsets) { std::vector machine_types; // used as sets because n is tiny std::vector directives; @@ -401,9 +424,23 @@ namespace { // Skip the header, no need to read it const auto coff_base = offset + sizeof(ArchiveMemberHeader); - Checks::check_exit(VCPKG_LINE_INFO, f.seek(coff_base, SEEK_SET) == 0); + { + auto seek = f.try_seek_to(coff_base); + if (!seek.has_value()) + { + return std::move(seek).error(); + } + } + uint32_t tag_sniffer; - Checks::check_exit(VCPKG_LINE_INFO, f.read(&tag_sniffer, sizeof(tag_sniffer), 1) == 1); + { + auto read = f.try_read_all(&tag_sniffer, sizeof(tag_sniffer)); + if (!read.has_value()) + { + return std::move(read).error(); + } + } + if (tag_sniffer == LlvmBitcodeSignature) { // obj is LLVM bitcode @@ -413,7 +450,14 @@ namespace { // obj is an import obj ImportHeaderAfterSignature import_header; - Checks::check_exit(VCPKG_LINE_INFO, f.read(&import_header, sizeof(import_header), 1) == 1); + { + auto read = f.try_read_all(&import_header, sizeof(import_header)); + if (!read.has_value()) + { + return std::move(read).error(); + } + } + add_machine_type(machine_types, static_cast(import_header.machine)); } else @@ -425,17 +469,35 @@ namespace add_machine_type(machine_types, static_cast(coff_signature.machine)); CoffFileHeaderAfterSignature coff_header; - Checks::check_exit(VCPKG_LINE_INFO, f.read(&coff_header, sizeof(coff_header), 1) == 1); + { + auto read = f.try_read_all(&coff_header, sizeof(coff_header)); + if (!read.has_value()) + { + return std::move(read).error(); + } + } // Object files shouldn't have optional headers, but the spec says we should skip over one if any - f.seek(coff_header.size_of_optional_header, SEEK_CUR); + { + auto seek = f.try_seek_to(coff_header.size_of_optional_header, SEEK_CUR); + if (!seek.has_value()) + { + return std::move(seek).error(); + } + } + // Read section headers std::vector sections; sections.resize(coff_signature.number_of_sections); - Checks::check_exit(VCPKG_LINE_INFO, - f.read(sections.data(), - sizeof(SectionTableHeader), - coff_signature.number_of_sections) == coff_signature.number_of_sections); + { + auto read = + f.try_read_all(sections.data(), sizeof(SectionTableHeader) * coff_signature.number_of_sections); + if (!read.has_value()) + { + return std::move(read).error(); + } + } + // Look for linker directive sections for (auto&& section : sections) { @@ -449,10 +511,22 @@ namespace // read the actual directive std::string directive_command_line; const auto section_offset = coff_base + section.pointer_to_raw_data; - Checks::check_exit(VCPKG_LINE_INFO, f.seek(section_offset, SEEK_SET) == 0); + { + auto seek = f.try_seek_to(section_offset); + if (!seek.has_value()) + { + return std::move(seek).error(); + } + } + directive_command_line.resize(section.size_of_raw_data); - auto fun = f.read(directive_command_line.data(), 1, section.size_of_raw_data); - Checks::check_exit(VCPKG_LINE_INFO, fun == section.size_of_raw_data); + { + auto read = f.try_read_all(directive_command_line.data(), section.size_of_raw_data); + if (!read.has_value()) + { + return std::move(read).error(); + } + } if (Strings::starts_with(directive_command_line, StringLiteral{"\xEF\xBB\xBF"})) { @@ -493,14 +567,6 @@ namespace vcpkg MachineType DllMetadata::get_machine_type() const noexcept { return static_cast(coff_header.machine); } - void ArchiveMemberHeader::check_end_of_header() const - { - // The name[0] == '\0' check is for freeglut, see GitHub issue #223 - Checks::msg_check_exit(VCPKG_LINE_INFO, - name[0] == '\0' || (end_of_header[0] == '`' && end_of_header[1] == '\n'), - msgIncorrectLibHeaderEnd); - } - uint64_t ArchiveMemberHeader::decoded_size() const { char size_plus_null[11]; @@ -738,15 +804,30 @@ namespace vcpkg }); } - LibInformation read_lib_information(const ReadFilePointer& f) + ExpectedL read_lib_information(ReadFilePointer& f) { - read_and_verify_archive_file_signature(f); - const auto first_offsets = try_read_first_linker_member_offsets(f); - const auto second_offsets = try_read_second_linker_member_offsets(f); + auto read_signature = read_and_verify_archive_file_signature(f); + if (!read_signature.has_value()) + { + return std::move(read_signature).error(); + } + + auto first_offsets = try_read_first_linker_member_offsets(f); + if (!first_offsets.has_value()) + { + return std::move(first_offsets).error(); + } + + auto second_offsets = try_read_second_linker_member_offsets(f); + if (!first_offsets.has_value()) + { + return std::move(first_offsets).error(); + } + const std::vector* offsets; // "Although both linker members provide a directory of symbols and archive members that // contain them, the second linker member is used in preference to the first by all current linkers." - if (auto maybe_offsets2 = second_offsets.get()) + if (auto maybe_offsets2 = second_offsets.get()->get()) { offsets = maybe_offsets2; } @@ -756,8 +837,7 @@ namespace vcpkg } else { - // FIXME message - Checks::exit_fail(VCPKG_LINE_INFO); + return msg::format_error(msgInvalidLibraryMissingLinkerMembers); } return read_lib_information_from_archive_members(f, *offsets); diff --git a/src/vcpkg/base/files.cpp b/src/vcpkg/base/files.cpp index 841722e231..6acdd89caf 100644 --- a/src/vcpkg/base/files.cpp +++ b/src/vcpkg/base/files.cpp @@ -1365,15 +1365,6 @@ namespace vcpkg FilePointer::operator bool() const noexcept { return m_fs != nullptr; } - int FilePointer::seek(long long offset, int origin) const noexcept - { -#if defined(_WIN32) - return ::_fseeki64(m_fs, offset, origin); -#else // ^^^ _WIN32 / !_WIN32 vvv - return ::fseeko(m_fs, offset, origin); -#endif // ^^^ !_WIN32 - } - long long FilePointer::tell() const noexcept { #if defined(_WIN32) @@ -1391,9 +1382,17 @@ namespace vcpkg const Path& FilePointer::path() const { return m_path; } - ExpectedL FilePointer::try_seek_to(long long offset) + ExpectedL FilePointer::try_seek_to(long long offset) { return try_seek_to(offset, SEEK_SET); } + + ExpectedL FilePointer::try_seek_to(long long offset, int origin) { - if (this->seek(offset, SEEK_SET)) +#if defined(_WIN32) + const int result = ::_fseeki64(m_fs, offset, origin); +#else // ^^^ _WIN32 / !_WIN32 vvv + const int result = ::fseeko(m_fs, offset, origin); +#endif // ^^^ !_WIN32 + + if (result) { return msg::format(msgFileSeekFailed, msg::path = m_path, msg::byte_offset = offset); } diff --git a/src/vcpkg/base/messages.cpp b/src/vcpkg/base/messages.cpp index cdbed1ae2c..71b955dd6c 100644 --- a/src/vcpkg/base/messages.cpp +++ b/src/vcpkg/base/messages.cpp @@ -723,7 +723,6 @@ namespace vcpkg REGISTER_MESSAGE(IllegalPlatformSpec); REGISTER_MESSAGE(ImproperShaLength); REGISTER_MESSAGE(IncorrectArchiveFileSignature); - REGISTER_MESSAGE(IncorrectLibHeaderEnd); REGISTER_MESSAGE(IncorrectPESignature); REGISTER_MESSAGE(IncorrectNumberOfArgs); REGISTER_MESSAGE(IncrementedUtf8Decoder); @@ -769,6 +768,7 @@ namespace vcpkg REGISTER_MESSAGE(InvalidFloatingPointConst); REGISTER_MESSAGE(InvalidHexDigit); REGISTER_MESSAGE(InvalidIntegerConst); + REGISTER_MESSAGE(InvalidLibraryMissingLinkerMembers); REGISTER_MESSAGE(InvalidPortVersonName); REGISTER_MESSAGE(InvalidString); REGISTER_MESSAGE(InvalidFileType); @@ -784,6 +784,8 @@ namespace vcpkg REGISTER_MESSAGE(JsonValueNotObject); REGISTER_MESSAGE(JsonValueNotString); REGISTER_MESSAGE(LaunchingProgramFailed); + REGISTER_MESSAGE(LibraryArchiveMemberTooSmall); + REGISTER_MESSAGE(LibraryFirstLinkerMemberMissing); REGISTER_MESSAGE(LicenseExpressionContainsExtraPlus); REGISTER_MESSAGE(LicenseExpressionContainsInvalidCharacter); REGISTER_MESSAGE(LicenseExpressionContainsUnicode); diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index e928049ecf..8f95260935 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -590,8 +590,8 @@ namespace vcpkg msgExpectedExtension, msg::extension = ".lib", msg::path = file); - - auto machine_types = read_lib_information(fs.open_for_read(file, VCPKG_LINE_INFO)).machine_types; + auto file_handle = fs.open_for_read(file, VCPKG_LINE_INFO); + auto machine_types = read_lib_information(file_handle).value_or_exit(VCPKG_LINE_INFO).machine_types; { auto llvm_bitcode = std::find(machine_types.begin(), machine_types.end(), MachineType::LLVM_BITCODE); @@ -932,7 +932,7 @@ namespace vcpkg for (const Path& lib : libs) { auto lib_file = fs.try_open_for_read(lib).value_or_exit(VCPKG_LINE_INFO); - auto lib_info = read_lib_information(lib_file); + auto lib_info = read_lib_information(lib_file).value_or_exit(VCPKG_LINE_INFO); Debug::println("The lib " + lib.native() + " has directives: " + Strings::join(" ", lib_info.linker_directives)); From 813ade6a852c739bed05cf2f289e435754ea951f Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 10 Jan 2023 13:40:51 -0800 Subject: [PATCH 18/33] Harden the post build checks that use the lib reader. --- include/vcpkg/base/messages.h | 4 ---- src/vcpkg/base/messages.cpp | 1 - src/vcpkg/postbuildlint.cpp | 32 +++++++++++++++++++++++--------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/include/vcpkg/base/messages.h b/include/vcpkg/base/messages.h index da9983e647..aa801183df 100644 --- a/include/vcpkg/base/messages.h +++ b/include/vcpkg/base/messages.h @@ -1220,10 +1220,6 @@ namespace vcpkg "{expected} is a locale-invariant delimiter; for example, the ':' or '=' in 'zlib:x64-windows=skip'", "expected '{expected}' here"); DECLARE_MESSAGE(ExpectedDigitsAfterDecimal, (), "", "Expected digits after the decimal point"); - DECLARE_MESSAGE(ExpectedExtension, - (msg::extension, msg::path), - "", - "The file extension was not {extension}: {path}"); DECLARE_MESSAGE(ExpectedFailOrSkip, (), "", "expected 'fail', 'skip', or 'pass' here"); DECLARE_MESSAGE(ExpectedOneSetOfTags, (msg::count, msg::old_value, msg::new_value, msg::value), diff --git a/src/vcpkg/base/messages.cpp b/src/vcpkg/base/messages.cpp index 71b955dd6c..49632dd6d1 100644 --- a/src/vcpkg/base/messages.cpp +++ b/src/vcpkg/base/messages.cpp @@ -1057,7 +1057,6 @@ namespace vcpkg REGISTER_MESSAGE(PortBugDllAppContainerBitNotSet); REGISTER_MESSAGE(BuiltWithIncorrectArchitecture); REGISTER_MESSAGE(BinaryWithInvalidArchitecture); - REGISTER_MESSAGE(ExpectedExtension); REGISTER_MESSAGE(FailedToDetermineArchitecture); REGISTER_MESSAGE(PortBugFoundDllInStaticBuild); REGISTER_MESSAGE(PortBugMismatchedNumberOfBinaries); diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index 8f95260935..29d54d1509 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -585,13 +585,20 @@ namespace vcpkg { for (const Path& file : files) { - Checks::msg_check_exit(VCPKG_LINE_INFO, - Strings::case_insensitive_ascii_equals(file.extension(), ".lib"), - msgExpectedExtension, - msg::extension = ".lib", - msg::path = file); - auto file_handle = fs.open_for_read(file, VCPKG_LINE_INFO); - auto machine_types = read_lib_information(file_handle).value_or_exit(VCPKG_LINE_INFO).machine_types; + if (!Strings::case_insensitive_ascii_equals(file.extension(), ".lib")) + { + continue; + } + + auto maybe_lib_information = fs.try_open_for_read(file).then( + [](ReadFilePointer&& file_handle) { return read_lib_information(file_handle); }); + + if (!maybe_lib_information.has_value()) + { + continue; + } + + auto&& machine_types = maybe_lib_information.value_or_exit(VCPKG_LINE_INFO).machine_types; { auto llvm_bitcode = std::find(machine_types.begin(), machine_types.end(), MachineType::LLVM_BITCODE); @@ -931,8 +938,15 @@ namespace vcpkg std::vector libs_with_invalid_crt; for (const Path& lib : libs) { - auto lib_file = fs.try_open_for_read(lib).value_or_exit(VCPKG_LINE_INFO); - auto lib_info = read_lib_information(lib_file).value_or_exit(VCPKG_LINE_INFO); + auto maybe_lib_info = fs.try_open_for_read(lib).then( + [](ReadFilePointer&& lib_file) { return read_lib_information(lib_file); }); + + if (!maybe_lib_info.has_value()) + { + continue; + } + + auto&& lib_info = maybe_lib_info.value_or_exit(VCPKG_LINE_INFO); Debug::println("The lib " + lib.native() + " has directives: " + Strings::join(" ", lib_info.linker_directives)); From 8aae6c86e49488dfbe81c82799d2032652bf5799 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 10 Jan 2023 14:37:14 -0800 Subject: [PATCH 19/33] generate-message-map --- locales/messages.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/locales/messages.json b/locales/messages.json index e6fc683912..768789f24f 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -437,8 +437,6 @@ "ExpectedCharacterHere": "expected '{expected}' here", "_ExpectedCharacterHere.comment": "{expected} is a locale-invariant delimiter; for example, the ':' or '=' in 'zlib:x64-windows=skip'", "ExpectedDigitsAfterDecimal": "Expected digits after the decimal point", - "ExpectedExtension": "The file extension was not {extension}: {path}", - "_ExpectedExtension.comment": "An example of {extension} is .exe. An example of {path} is /foo/bar.", "ExpectedFailOrSkip": "expected 'fail', 'skip', or 'pass' here", "ExpectedOneSetOfTags": "Found {count} sets of {old_value}.*{new_value} but expected exactly 1, in block:\n{value}", "_ExpectedOneSetOfTags.comment": "{old_value} is a left tag and {new_value} is the right tag. {value} is the input. An example of {count} is 42.", From a74ed3fd33835469cfe3d73b8558b8530f7da202 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 10 Jan 2023 15:31:40 -0800 Subject: [PATCH 20/33] formatting --- include/vcpkg/base/lineinfo.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/vcpkg/base/lineinfo.h b/include/vcpkg/base/lineinfo.h index 68fca2e0e8..29b8ede563 100644 --- a/include/vcpkg/base/lineinfo.h +++ b/include/vcpkg/base/lineinfo.h @@ -10,4 +10,7 @@ namespace vcpkg } #define VCPKG_LINE_INFO \ - vcpkg::LineInfo { __LINE__, __FILE__ } + vcpkg::LineInfo \ + { \ + __LINE__, __FILE__ \ + } From adfb8abed3720d069b7ebbd304ad621f01d1f2e4 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 18 Jan 2023 20:07:50 -0800 Subject: [PATCH 21/33] Fix build failure. --- src/vcpkg/base/cofffilereader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vcpkg/base/cofffilereader.cpp b/src/vcpkg/base/cofffilereader.cpp index ee38be9e09..e69576083c 100644 --- a/src/vcpkg/base/cofffilereader.cpp +++ b/src/vcpkg/base/cofffilereader.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include From 480dd223084af0f9919db0db3b26486db704473a Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 6 Feb 2023 15:31:14 -0800 Subject: [PATCH 22/33] Define _FILE_OFFSET_BITS=64 --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef1d8e7ab5..712b09c03e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -215,6 +215,7 @@ target_include_directories(vcpkglib PUBLIC include) target_compile_definitions(vcpkglib PUBLIC VCPKG_VERSION=${VCPKG_VERSION} VCPKG_BASE_VERSION=${VCPKG_BASE_VERSION} + _FILE_OFFSET_BITS=64 ) if(NOT DEFINED VCPKG_STANDALONE_BUNDLE_SHA OR VCPKG_STANDALONE_BUNDLE_SHA STREQUAL "") From 60fae76c832b6d5f1b6525b80248117199796716 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 6 Feb 2023 16:27:51 -0800 Subject: [PATCH 23/33] Use TestingRoot rather than manually cleaning WorkingRoot. --- .../post-build-checks.ps1 | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 index 8f88837d02..dcb39babf9 100644 --- a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 @@ -16,16 +16,12 @@ if (-not $buildOutput.Contains("$packagesRoot\vcpkg-internal-dll-with-no-exports # DLLs with wrong architecture Refresh-TestRoot -if (Test-Path "$WorkingRoot/wrong-architecture") { - Remove-Item "$WorkingRoot/wrong-architecture" -Recurse -Force -} - -mkdir "$WorkingRoot/wrong-architecture" -Copy-Item -Recurse "$PSScriptRoot/../e2e_assets/test-dll-port-template" "$WorkingRoot/wrong-architecture/test-dll" -Run-Vcpkg env "$WorkingRoot/wrong-architecture/test-dll/build.cmd" --Triplet x64-windows +mkdir "$TestingRoot/wrong-architecture" +Copy-Item -Recurse "$PSScriptRoot/../e2e_assets/test-dll-port-template" "$TestingRoot/wrong-architecture/test-dll" +Run-Vcpkg env "$TestingRoot/wrong-architecture/test-dll/build.cmd" --Triplet x64-windows Throw-IfFailed -$buildOutput = Run-VcpkgAndCaptureOutput @commonArgs install --overlay-ports="$WorkingRoot/wrong-architecture" test-dll --no-binarycaching +$buildOutput = Run-VcpkgAndCaptureOutput @commonArgs install --overlay-ports="$TestingRoot/wrong-architecture" test-dll --no-binarycaching $expected = "warning: The following files were built for an incorrect architecture:`n" + ` "warning: $packagesRoot\test-dll_x86-windows\debug\lib\test_dll.lib`n" + ` " Expected: x86, but was x64`n" + ` @@ -43,16 +39,12 @@ if (-not $buildOutput.Replace("`r`n", "`n").Contains($expected)) { # DLLs with no AppContainer bit Refresh-TestRoot -if (Test-Path "$WorkingRoot/wrong-appcontainer") { - Remove-Item "$WorkingRoot/wrong-appcontainer" -Recurse -Force -} - -mkdir "$WorkingRoot/wrong-appcontainer" -Copy-Item -Recurse "$PSScriptRoot/../e2e_assets/test-dll-port-template" "$WorkingRoot/wrong-appcontainer/test-dll" -Run-Vcpkg env "$WorkingRoot/wrong-appcontainer/test-dll/build.cmd" --Triplet x64-windows +mkdir "$TestingRoot/wrong-appcontainer" +Copy-Item -Recurse "$PSScriptRoot/../e2e_assets/test-dll-port-template" "$TestingRoot/wrong-appcontainer/test-dll" +Run-Vcpkg env "$TestingRoot/wrong-appcontainer/test-dll/build.cmd" --Triplet x64-windows Throw-IfFailed -$buildOutput = Run-VcpkgAndCaptureOutput --triplet x64-uwp "--x-buildtrees-root=$buildtreesRoot" "--x-install-root=$installRoot" "--x-packages-root=$packagesRoot" install --overlay-ports="$WorkingRoot/wrong-appcontainer" test-dll --no-binarycaching +$buildOutput = Run-VcpkgAndCaptureOutput --triplet x64-uwp "--x-buildtrees-root=$buildtreesRoot" "--x-install-root=$installRoot" "--x-packages-root=$packagesRoot" install --overlay-ports="$TestingRoot/wrong-appcontainer" test-dll --no-binarycaching $expected = "warning: The App Container bit must be set for Windows Store apps. The following DLLs do not have the App Container bit set:`n" + ` "`n" + ` " $packagesRoot\test-dll_x64-uwp\debug\bin\test_dll.dll`n" + ` @@ -64,16 +56,12 @@ if (-not $buildOutput.Replace("`r`n", "`n").Contains($expected)) { # Wrong CRT linkage Refresh-TestRoot -if (Test-Path "$WorkingRoot/wrong-crt") { - Remove-Item "$WorkingRoot/wrong-crt" -Recurse -Force -} - -mkdir "$WorkingRoot/wrong-crt" -Copy-Item -Recurse "$PSScriptRoot/../e2e_assets/test-lib-port-template-dynamic-crt" "$WorkingRoot/wrong-crt/test-lib" -Run-Vcpkg env "$WorkingRoot/wrong-crt/test-lib/build.cmd" --Triplet x86-windows-static +mkdir "$TestingRoot/wrong-crt" +Copy-Item -Recurse "$PSScriptRoot/../e2e_assets/test-lib-port-template-dynamic-crt" "$TestingRoot/wrong-crt/test-lib" +Run-Vcpkg env "$TestingRoot/wrong-crt/test-lib/build.cmd" --Triplet x86-windows-static Throw-IfFailed -$buildOutput = Run-VcpkgAndCaptureOutput --triplet x86-windows-static "--x-buildtrees-root=$buildtreesRoot" "--x-install-root=$installRoot" "--x-packages-root=$packagesRoot" install --overlay-ports="$WorkingRoot/wrong-crt" test-lib --no-binarycaching +$buildOutput = Run-VcpkgAndCaptureOutput --triplet x86-windows-static "--x-buildtrees-root=$buildtreesRoot" "--x-install-root=$installRoot" "--x-packages-root=$packagesRoot" install --overlay-ports="$TestingRoot/wrong-crt" test-lib --no-binarycaching $expected = "warning: The following binaries should use the Static Release CRT.`n" + " $packagesRoot\test-lib_x86-windows-static\debug\lib\both_lib.lib links with:`n" + " Dynamic Debug`n" + From bb62d9d064f93f7f6d5acb55be971b3aa8ed2698 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 6 Feb 2023 16:28:04 -0800 Subject: [PATCH 24/33] Add command line flags to CRT kinds. --- include/vcpkg/base/messages.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/vcpkg/base/messages.h b/include/vcpkg/base/messages.h index c133a42c94..dcdc577fd1 100644 --- a/include/vcpkg/base/messages.h +++ b/include/vcpkg/base/messages.h @@ -1824,10 +1824,10 @@ namespace vcpkg (msg::value), "Example of {value} is 'unknownlicense'", "Unknown license identifier '{value}'. Known values are listed at https://spdx.org/licenses/"); - DECLARE_MESSAGE(LinkageDynamicDebug, (), "", "Dynamic Debug"); - DECLARE_MESSAGE(LinkageDynamicRelease, (), "", "Dynamic Release"); - DECLARE_MESSAGE(LinkageStaticDebug, (), "", "Static Debug"); - DECLARE_MESSAGE(LinkageStaticRelease, (), "", "Static Release"); + DECLARE_MESSAGE(LinkageDynamicDebug, (), "", "Dynamic Debug (/MDd)"); + DECLARE_MESSAGE(LinkageDynamicRelease, (), "", "Dynamic Release (/MD)"); + DECLARE_MESSAGE(LinkageStaticDebug, (), "", "Static Debug (/MTd)"); + DECLARE_MESSAGE(LinkageStaticRelease, (), "", "Static Release (/MT)"); DECLARE_MESSAGE(ListOfValidFieldsForControlFiles, (), "", From 4b65e29a945b4e4c156cde80fef2af8044187262 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 6 Feb 2023 16:39:24 -0800 Subject: [PATCH 25/33] Some CR fixes. --- src/vcpkg/base/cofffilereader.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vcpkg/base/cofffilereader.cpp b/src/vcpkg/base/cofffilereader.cpp index e69576083c..3ed291a633 100644 --- a/src/vcpkg/base/cofffilereader.cpp +++ b/src/vcpkg/base/cofffilereader.cpp @@ -262,7 +262,7 @@ namespace static constexpr StringLiteral FILE_START = "!\n"; static constexpr auto FILE_START_SIZE = FILE_START.size(); return f.try_seek_to(0).then([&f](Unit) -> ExpectedL { - char file_start[FILE_START.size()]; + char file_start[FILE_START_SIZE]; auto result = f.try_read_all(file_start, FILE_START_SIZE); if (result.has_value() && FILE_START != StringView{file_start, FILE_START_SIZE}) { @@ -325,9 +325,8 @@ namespace offset = bswap(offset); } - Util::sort_unique_erase(offsets); offsets.erase(std::remove(offsets.begin(), offsets.end(), 0u), offsets.end()); - std::sort(offsets.begin(), offsets.end()); + Util::sort_unique_erase(offsets); uint64_t leftover = first_size - sizeof(uint32_t) - (archive_symbol_count * sizeof(uint32_t)); { auto seek = f.try_seek_to(leftover, SEEK_CUR); @@ -820,9 +819,9 @@ namespace vcpkg } auto second_offsets = try_read_second_linker_member_offsets(f); - if (!first_offsets.has_value()) + if (!second_offsets.has_value()) { - return std::move(first_offsets).error(); + return std::move(second_offsets).error(); } const std::vector* offsets; From 8bb25d2f5ec1dcf9d975fc00c6198d5ef81a07ce Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 6 Feb 2023 20:08:30 -0800 Subject: [PATCH 26/33] Use a real set for linker directives. --- include/vcpkg/base/cofffilereader.h | 6 ++++-- src/vcpkg/base/cofffilereader.cpp | 11 +++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/include/vcpkg/base/cofffilereader.h b/include/vcpkg/base/cofffilereader.h index d758d1cd1b..63af58278c 100644 --- a/include/vcpkg/base/cofffilereader.h +++ b/include/vcpkg/base/cofffilereader.h @@ -7,6 +7,8 @@ #include +#include +#include #include #include @@ -409,8 +411,8 @@ namespace vcpkg struct LibInformation { - std::vector machine_types; - std::vector linker_directives; + std::vector machine_types; // used as set because n is tiny + std::set> linker_directives; }; std::vector tokenize_command_line(StringView cmd_line); diff --git a/src/vcpkg/base/cofffilereader.cpp b/src/vcpkg/base/cofffilereader.cpp index 3ed291a633..30fb36fd61 100644 --- a/src/vcpkg/base/cofffilereader.cpp +++ b/src/vcpkg/base/cofffilereader.cpp @@ -417,8 +417,8 @@ namespace ExpectedL read_lib_information_from_archive_members(ReadFilePointer& f, const std::vector& member_offsets) { - std::vector machine_types; // used as sets because n is tiny - std::vector directives; + std::vector machine_types; // used as set because n is tiny + std::set> directives; // Next we have the obj and pseudo-object files for (unsigned int offset : member_offsets) { @@ -536,12 +536,7 @@ namespace for (auto&& directive : tokenize_command_line(directive_command_line)) { - auto insertion_point = - std::lower_bound(directives.begin(), directives.end(), directive_command_line); - if (insertion_point == directives.end() || *insertion_point != directive) - { - directives.insert(insertion_point, std::move(directive)); - } + directives.insert(std::move(directive)); } } } From 18e2fa5bdd0f0e28f28d2cc842e7cc1ec379e835 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 6 Feb 2023 20:10:21 -0800 Subject: [PATCH 27/33] Remove more dumpbin leftovers. --- src/vcpkg/visualstudio.cpp | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/vcpkg/visualstudio.cpp b/src/vcpkg/visualstudio.cpp index 74f5101a2e..dd316fbfae 100644 --- a/src/vcpkg/visualstudio.cpp +++ b/src/vcpkg/visualstudio.cpp @@ -307,37 +307,47 @@ namespace vcpkg::VisualStudio if (major_version == "14" || major_version == "12") { const auto vcvarsall_bat = vs_instance.root_path / "VC/vcvarsall.bat"; - paths_examined.push_back(vcvarsall_bat); if (fs.exists(vcvarsall_bat, IgnoreErrors{})) { - const auto vs_dumpbin_dir = vs_instance.root_path / "VC/bin"; - const auto vs_dumpbin_exe = vs_dumpbin_dir / "dumpbin.exe"; - paths_examined.push_back(vs_dumpbin_exe); - const auto vs_bin_dir = Path(vcvarsall_bat.parent_path()) / "bin"; std::vector supported_architectures; if (fs.exists(vs_bin_dir / "vcvars32.bat", IgnoreErrors{})) + { supported_architectures.push_back({"x86", CPU::X86, CPU::X86}); + } + if (fs.exists(vs_bin_dir / "amd64/vcvars64.bat", IgnoreErrors{})) + { supported_architectures.push_back({"x64", CPU::X64, CPU::X64}); + } + if (fs.exists(vs_bin_dir / "x86_amd64/vcvarsx86_amd64.bat", IgnoreErrors{})) + { supported_architectures.push_back({"x86_amd64", CPU::X86, CPU::X64}); + } + if (fs.exists(vs_bin_dir / "x86_arm/vcvarsx86_arm.bat", IgnoreErrors{})) + { supported_architectures.push_back({"x86_arm", CPU::X86, CPU::ARM}); + } + if (fs.exists(vs_bin_dir / "amd64_x86/vcvarsamd64_x86.bat", IgnoreErrors{})) + { supported_architectures.push_back({"amd64_x86", CPU::X64, CPU::X86}); + } + if (fs.exists(vs_bin_dir / "amd64_arm/vcvarsamd64_arm.bat", IgnoreErrors{})) + { supported_architectures.push_back({"amd64_arm", CPU::X64, CPU::ARM}); + } - const Toolset toolset = {vs_instance.root_path, - vcvarsall_bat, - {}, - major_version == "14" ? V_140 : V_120, - major_version, - supported_architectures}; - - found_toolsets.push_back(toolset); + found_toolsets.push_back(Toolset{vs_instance.root_path, + vcvarsall_bat, + {}, + major_version == "14" ? V_140 : V_120, + major_version, + supported_architectures}); } } } From a48dfc7e3a374da9ce0ac97fbaf4a63e9fed3359 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 6 Feb 2023 20:36:36 -0800 Subject: [PATCH 28/33] Fix case sensitivity in old CRTs check. Drive by: Get rid of dynamic initializers for old CRTs lists. --- include/vcpkg/base/util.h | 17 +++++++-- locales/messages.json | 10 +++-- src/vcpkg/binarycaching.cpp | 2 +- src/vcpkg/postbuildlint.cpp | 73 ++++++++++++++++++------------------- 4 files changed, 57 insertions(+), 45 deletions(-) diff --git a/include/vcpkg/base/util.h b/include/vcpkg/base/util.h index 6a86dcf646..34505b0a32 100644 --- a/include/vcpkg/base/util.h +++ b/include/vcpkg/base/util.h @@ -24,12 +24,23 @@ namespace vcpkg::Util { augend->insert(augend->end(), addend.begin(), addend.end()); } + template + bool contains(const Vec& container, const Key& item, KeyEqual key_equal) + { + for (auto&& citem : container) + { + if (key_equal(citem, item)) + { + return true; + } + } + + return false; + } template bool contains(const Vec& container, const Key& item) { - using std::begin; - using std::end; - return std::find(begin(container), end(container), item) != end(container); + return std::find(container.begin(), container.end(), item) != container.end(); } template std::vector concat(View r1, View r2) diff --git a/locales/messages.json b/locales/messages.json index 00ae433687..f95f04d736 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -788,10 +788,10 @@ "_LicenseExpressionUnknownException.comment": "Example of {value} is 'unknownexception'", "LicenseExpressionUnknownLicense": "Unknown license identifier '{value}'. Known values are listed at https://spdx.org/licenses/", "_LicenseExpressionUnknownLicense.comment": "Example of {value} is 'unknownlicense'", - "LinkageDynamicDebug": "Dynamic Debug", - "LinkageDynamicRelease": "Dynamic Release", - "LinkageStaticDebug": "Static Debug", - "LinkageStaticRelease": "Static Release", + "LinkageDynamicDebug": "Dynamic Debug (/MDd)", + "LinkageDynamicRelease": "Dynamic Release (/MD)", + "LinkageStaticDebug": "Static Debug (/MTd)", + "LinkageStaticRelease": "Static Release (/MT)", "ListOfValidFieldsForControlFiles": "This is the list of valid fields for CONTROL files (case-sensitive):", "LoadingCommunityTriplet": "-- [COMMUNITY] Loading triplet configuration from: {path}", "_LoadingCommunityTriplet.comment": "'-- [COMMUNITY]' at the beginning must be preserved An example of {path} is /foo/bar.", @@ -957,6 +957,8 @@ "PortBugMissingIncludeDir": "The folder /include is empty or not present. This indicates the library was not correctly installed.", "PortBugMissingLicense": "The software license must be available at ${{CURRENT_PACKAGES_DIR}}/share/{spec}/copyright", "_PortBugMissingLicense.comment": "An example of {spec} is zlib:x64-windows.", + "PortBugMissingProvidedUsage": "The port provided \"usage\" but forgot to install to /share/{spec}/usage, add the following linein the portfile:", + "_PortBugMissingProvidedUsage.comment": "An example of {spec} is zlib:x64-windows.", "PortBugMissingReleaseBinaries": "Release binaries were not found.", "PortBugMovePkgConfigFiles": "You can move the pkgconfig files with commands similar to:", "PortBugOutdatedCRT": "Detected outdated dynamic CRT in the following files:", diff --git a/src/vcpkg/binarycaching.cpp b/src/vcpkg/binarycaching.cpp index 5dc4143ad9..a63eae4dea 100644 --- a/src/vcpkg/binarycaching.cpp +++ b/src/vcpkg/binarycaching.cpp @@ -1255,7 +1255,7 @@ namespace vcpkg { std::vector invalid_keys; auto result = api_stable_format(url_template, [&](std::string&, StringView key) { - StringView valid_keys[] = {"name", "version", "sha", "triplet"}; + static constexpr std::array valid_keys = {"name", "version", "sha", "triplet"}; if (!Util::Vectors::contains(valid_keys, key)) { invalid_keys.push_back(key.to_string()); diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index 2719931c6c..bf9d55bc36 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -14,7 +14,7 @@ namespace vcpkg { - constexpr static const StringLiteral windows_system_names[] = { + constexpr static std::array windows_system_names = { "", "Windows", "WindowsStore", @@ -27,39 +27,37 @@ namespace vcpkg PROBLEM_DETECTED = 1 }; - struct OutdatedDynamicCrt + // clang-format off +#define OUTDATED_V_NO_120 \ + StringLiteral{"msvcp100.dll"}, \ + StringLiteral{"msvcp100d.dll"}, \ + StringLiteral{"msvcp110.dll"}, \ + StringLiteral{"msvcp110_win.dll"}, \ + StringLiteral{"msvcp60.dll"}, \ + StringLiteral{"msvcp60.dll"}, \ + \ + StringLiteral{"msvcrt.dll"}, \ + StringLiteral{"msvcr100.dll"}, \ + StringLiteral{"msvcr100d.dll"}, \ + StringLiteral{"msvcr100_clr0400.dll"}, \ + StringLiteral{"msvcr110.dll"}, \ + StringLiteral{"msvcrt20.dll"}, \ + StringLiteral{"msvcrt40.dll"} + + // clang-format on + + static View get_outdated_dynamic_crts(const Optional& toolset_version) { - std::string name; - }; - - static Span get_outdated_dynamic_crts(const Optional& toolset_version) - { - static const std::vector V_NO_120 = { - {"msvcp100.dll"}, - {"msvcp100d.dll"}, - {"msvcp110.dll"}, - {"msvcp110_win.dll"}, - {"msvcp60.dll"}, - {"msvcp60.dll"}, - - {"msvcrt.dll"}, - {"msvcr100.dll"}, - {"msvcr100d.dll"}, - {"msvcr100_clr0400.dll"}, - {"msvcr110.dll"}, - {"msvcrt20.dll"}, - {"msvcrt40.dll"}, + static constexpr std::array V_NO_120 = {OUTDATED_V_NO_120}; + + static constexpr std::array V_NO_MSVCRT = { + OUTDATED_V_NO_120, + StringLiteral{"msvcp120.dll"}, + StringLiteral{"msvcp120_clr0400.dll"}, + StringLiteral{"msvcr120.dll"}, + StringLiteral{"msvcr120_clr0400.dll"}, }; - static const std::vector V_NO_MSVCRT = [&]() { - auto ret = V_NO_120; - ret.push_back({"msvcp120.dll"}); - ret.push_back({"msvcp120_clr0400.dll"}); - ret.push_back({"msvcr120.dll"}); - ret.push_back({"msvcr120_clr0400.dll"}); - return ret; - }(); - const auto tsv = toolset_version.get(); if (tsv && (*tsv) == "v120") { @@ -70,6 +68,8 @@ namespace vcpkg return V_NO_MSVCRT; } +#undef OUTDATED_V_NO_120 + static LintStatus check_for_files_in_include_directory(const Filesystem& fs, const BuildPolicies& policies, const Path& package_dir) @@ -958,8 +958,6 @@ namespace vcpkg bool expect_release, const std::vector& libs) { - (void)build_info; - (void)expect_release; std::vector libs_with_invalid_crt; for (const Path& lib : libs) { @@ -1084,7 +1082,7 @@ namespace vcpkg struct OutdatedDynamicCrtAndFile { Path file; - OutdatedDynamicCrt outdated_crt; + StringLiteral outdated_crt; }; static LintStatus check_outdated_crt_linkage_of_dlls(const std::vector& dlls, @@ -1098,9 +1096,10 @@ namespace vcpkg for (const PostBuildCheckDllData& dll_data : dlls) { - for (const OutdatedDynamicCrt& outdated_crt : outdated_crts) + for (const StringLiteral& outdated_crt : outdated_crts) { - if (Util::Vectors::contains(dll_data.dependencies, outdated_crt.name)) + if (Util::Vectors::contains( + dll_data.dependencies, outdated_crt, Strings::case_insensitive_ascii_equals)) { dlls_with_outdated_crt.push_back({dll_data.path, outdated_crt}); break; @@ -1114,7 +1113,7 @@ namespace vcpkg for (const OutdatedDynamicCrtAndFile& btf : dlls_with_outdated_crt) { msg::write_unlocalized_text_to_stdout(Color::warning, - fmt::format(" {}:{}\n", btf.file, btf.outdated_crt.name)); + fmt::format(" {}:{}\n", btf.file, btf.outdated_crt)); } msg::println(msg::format(msgPortBugInspectFiles, msg::extension = "dll") .append_raw("\n dumpbin.exe /dependents mylibfile.dll")); From 86a8a5b7f9107330867579ee653c59c80854e0f7 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 6 Feb 2023 21:47:37 -0800 Subject: [PATCH 29/33] Extract append_floating_list. Change appends of single chars to call the char overload. Fix test failures. --- .../post-build-checks.ps1 | 16 ++-- include/vcpkg/base/messages.h | 87 ++++++------------- src/vcpkg-test/messages.cpp | 12 +++ src/vcpkg/base/messages.cpp | 84 ++++++++++++++++++ src/vcpkg/commands.add-version.cpp | 2 +- src/vcpkg/configuration.cpp | 14 +-- src/vcpkg/postbuildlint.cpp | 31 +++---- src/vcpkg/sourceparagraph.cpp | 6 +- src/vcpkg/tools.cpp | 20 ++--- 9 files changed, 163 insertions(+), 109 deletions(-) diff --git a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 index dcb39babf9..5436696f11 100644 --- a/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/post-build-checks.ps1 @@ -62,18 +62,18 @@ Run-Vcpkg env "$TestingRoot/wrong-crt/test-lib/build.cmd" --Triplet x86-windows- Throw-IfFailed $buildOutput = Run-VcpkgAndCaptureOutput --triplet x86-windows-static "--x-buildtrees-root=$buildtreesRoot" "--x-install-root=$installRoot" "--x-packages-root=$packagesRoot" install --overlay-ports="$TestingRoot/wrong-crt" test-lib --no-binarycaching -$expected = "warning: The following binaries should use the Static Release CRT.`n" + +$expected = "warning: The following binaries should use the Static Debug (/MTd) CRT.`n" + " $packagesRoot\test-lib_x86-windows-static\debug\lib\both_lib.lib links with:`n" + -" Dynamic Debug`n" + -" Dynamic Release`n" + -" $packagesRoot\test-lib_x86-windows-static\debug\lib\test_lib.lib links with: Dynamic Debug`n" + +" Dynamic Debug (/MDd)`n" + +" Dynamic Release (/MD)`n" + +" $packagesRoot\test-lib_x86-windows-static\debug\lib\test_lib.lib links with: Dynamic Debug (/MDd)`n" + "To inspect the lib files, use:`n" + " dumpbin.exe /directives mylibfile.lib`n" + -"warning: The following binaries should use the Static Release CRT.`n" + +"warning: The following binaries should use the Static Release (/MT) CRT.`n" + " $packagesRoot\test-lib_x86-windows-static\lib\both_lib.lib links with:`n" + -" Dynamic Debug`n" + -" Dynamic Release`n" + -" $packagesRoot\test-lib_x86-windows-static\lib\test_lib.lib links with: Dynamic Release`n" + +" Dynamic Debug (/MDd)`n" + +" Dynamic Release (/MD)`n" + +" $packagesRoot\test-lib_x86-windows-static\lib\test_lib.lib links with: Dynamic Release (/MD)`n" + "To inspect the lib files, use:`n" + " dumpbin.exe /directives mylibfile.lib`n" if (-not $buildOutput.Replace("`r`n", "`n").Contains($expected)) { diff --git a/include/vcpkg/base/messages.h b/include/vcpkg/base/messages.h index dcdc577fd1..3745fe9488 100644 --- a/include/vcpkg/base/messages.h +++ b/include/vcpkg/base/messages.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -27,91 +28,55 @@ namespace vcpkg struct LocalizedString { LocalizedString() = default; - operator StringView() const noexcept { return m_data; } - const std::string& data() const noexcept { return m_data; } - const std::string& to_string() const noexcept { return m_data; } - std::string extract_data() { return std::exchange(m_data, ""); } + operator StringView() const noexcept; + const std::string& data() const noexcept; + const std::string& to_string() const noexcept; + std::string extract_data(); - static LocalizedString from_raw(std::string&& s) { return LocalizedString(std::move(s)); } + static LocalizedString from_raw(std::string&& s) noexcept; template, int> = 0> static LocalizedString from_raw(const StringLike& s) { return LocalizedString(StringView(s)); } - LocalizedString& append_raw(char c) - { - m_data.push_back(c); - return *this; - } - LocalizedString& append_raw(StringView s) - { - m_data.append(s.begin(), s.size()); - return *this; - } + + LocalizedString& append_raw(char c); + LocalizedString& append_raw(StringView s); template LocalizedString& append_fmt_raw(fmt::format_string s, Args&&... args) { m_data.append(fmt::format(s, std::forward(args)...)); return *this; } - LocalizedString& append(const LocalizedString& s) - { - m_data.append(s.m_data); - return *this; - } + LocalizedString& append(const LocalizedString& s); template LocalizedString& append(Message m, const Args&... args) { return append(msg::format(m, args...)); } - LocalizedString& append_indent(size_t indent = 1) - { - m_data.append(indent * 4, ' '); - return *this; - } - - friend const char* to_printf_arg(const LocalizedString& s) { return s.data().c_str(); } - - friend bool operator==(const LocalizedString& lhs, const LocalizedString& rhs) - { - return lhs.data() == rhs.data(); - } - - friend bool operator!=(const LocalizedString& lhs, const LocalizedString& rhs) - { - return lhs.data() != rhs.data(); - } - - friend bool operator<(const LocalizedString& lhs, const LocalizedString& rhs) - { - return lhs.data() < rhs.data(); - } - - friend bool operator<=(const LocalizedString& lhs, const LocalizedString& rhs) - { - return lhs.data() <= rhs.data(); - } - - friend bool operator>(const LocalizedString& lhs, const LocalizedString& rhs) - { - return lhs.data() > rhs.data(); - } - - friend bool operator>=(const LocalizedString& lhs, const LocalizedString& rhs) - { - return lhs.data() >= rhs.data(); - } + LocalizedString& append_indent(size_t indent = 1); - bool empty() const { return m_data.empty(); } - void clear() { m_data.clear(); } + // 0 items - Does nothing + // 1 item - .append_raw(' ').append(item) + // 2+ items - foreach: .append_raw('\n').append_indent(indent).append(item) + LocalizedString& append_floating_list(int indent, View items); + friend const char* to_printf_arg(const LocalizedString& s) noexcept; + friend bool operator==(const LocalizedString& lhs, const LocalizedString& rhs) noexcept; + friend bool operator!=(const LocalizedString& lhs, const LocalizedString& rhs) noexcept; + friend bool operator<(const LocalizedString& lhs, const LocalizedString& rhs) noexcept; + friend bool operator<=(const LocalizedString& lhs, const LocalizedString& rhs) noexcept; + friend bool operator>(const LocalizedString& lhs, const LocalizedString& rhs) noexcept; + friend bool operator>=(const LocalizedString& lhs, const LocalizedString& rhs) noexcept; + bool empty() const noexcept; + void clear() noexcept; private: std::string m_data; - explicit LocalizedString(StringView data) : m_data(data.data(), data.size()) { } - explicit LocalizedString(std::string&& data) : m_data(std::move(data)) { } + explicit LocalizedString(StringView data); + explicit LocalizedString(std::string&& data) noexcept; }; } diff --git a/src/vcpkg-test/messages.cpp b/src/vcpkg-test/messages.cpp index f8e0a13dac..fd988ab0fe 100644 --- a/src/vcpkg-test/messages.cpp +++ b/src/vcpkg-test/messages.cpp @@ -8,6 +8,18 @@ using namespace vcpkg; using namespace vcpkg::Commands; +TEST_CASE ("append floaging list", "[LocalizedString]") +{ + const auto a = LocalizedString::from_raw("a"); + const auto b = LocalizedString::from_raw("b"); + CHECK(LocalizedString().append_floating_list(2, std::vector{}) == LocalizedString()); + CHECK(LocalizedString().append_floating_list(2, std::vector{a}) == + LocalizedString::from_raw(" a")); + const auto expected = LocalizedString::from_raw(" heading\n a\n b"); + CHECK(LocalizedString::from_raw(" heading").append_floating_list(2, std::vector{a, b}) == + expected); +} + TEST_CASE ("get path to locale from LCID", "[messages]") { // valid LCID; Chinese diff --git a/src/vcpkg/base/messages.cpp b/src/vcpkg/base/messages.cpp index 981d9064c5..5c695fe9de 100644 --- a/src/vcpkg/base/messages.cpp +++ b/src/vcpkg/base/messages.cpp @@ -13,6 +13,90 @@ CMRC_DECLARE(cmakerc); using namespace vcpkg; +namespace vcpkg +{ + LocalizedString::operator StringView() const noexcept { return m_data; } + const std::string& LocalizedString::data() const noexcept { return m_data; } + const std::string& LocalizedString::to_string() const noexcept { return m_data; } + std::string LocalizedString::extract_data() { return std::exchange(m_data, std::string{}); } + + LocalizedString LocalizedString::from_raw(std::string&& s) noexcept { return LocalizedString(std::move(s)); } + + LocalizedString& LocalizedString::append_raw(char c) + { + m_data.push_back(c); + return *this; + } + + LocalizedString& LocalizedString::append_raw(StringView s) + { + m_data.append(s.begin(), s.size()); + return *this; + } + + LocalizedString& LocalizedString::append(const LocalizedString& s) + { + m_data.append(s.m_data); + return *this; + } + + LocalizedString& LocalizedString::append_indent(size_t indent) + { + m_data.append(indent * 4, ' '); + return *this; + } + + LocalizedString& LocalizedString::append_floating_list(int indent, View items) + { + switch (items.size()) + { + case 0: break; + case 1: append_raw(' ').append(items[0]); break; + default: + for (auto&& item : items) + { + append_raw('\n').append_indent(indent).append(item); + } + + break; + } + + return *this; + } + + const char* to_printf_arg(const LocalizedString& s) noexcept { return s.data().c_str(); } + + bool operator==(const LocalizedString& lhs, const LocalizedString& rhs) noexcept + { + return lhs.data() == rhs.data(); + } + + bool operator!=(const LocalizedString& lhs, const LocalizedString& rhs) noexcept + { + return lhs.data() != rhs.data(); + } + + bool operator<(const LocalizedString& lhs, const LocalizedString& rhs) noexcept { return lhs.data() < rhs.data(); } + + bool operator<=(const LocalizedString& lhs, const LocalizedString& rhs) noexcept + { + return lhs.data() <= rhs.data(); + } + + bool operator>(const LocalizedString& lhs, const LocalizedString& rhs) noexcept { return lhs.data() > rhs.data(); } + + bool operator>=(const LocalizedString& lhs, const LocalizedString& rhs) noexcept + { + return lhs.data() >= rhs.data(); + } + + bool LocalizedString::empty() const noexcept { return m_data.empty(); } + void LocalizedString::clear() noexcept { m_data.clear(); } + + LocalizedString::LocalizedString(StringView data) : m_data(data.data(), data.size()) { } + LocalizedString::LocalizedString(std::string&& data) noexcept : m_data(std::move(data)) { } +} + namespace vcpkg::msg { REGISTER_MESSAGE(SeeURL); diff --git a/src/vcpkg/commands.add-version.cpp b/src/vcpkg/commands.add-version.cpp index 19ae6508ae..74e7883b36 100644 --- a/src/vcpkg/commands.add-version.cpp +++ b/src/vcpkg/commands.add-version.cpp @@ -209,7 +209,7 @@ namespace msg::format(msgAddVersionAddedVersionToFile, msg::version = port_version.version, msg::path = version_db_file_path) - .append_raw(" ") + .append_raw(' ') .append(msgAddVersionNewFile)); } return UpdateResult::Updated; diff --git a/src/vcpkg/configuration.cpp b/src/vcpkg/configuration.cpp index 9756ad8110..d3fcb68c5b 100644 --- a/src/vcpkg/configuration.cpp +++ b/src/vcpkg/configuration.cpp @@ -389,10 +389,10 @@ namespace { return msg.append_indent(indent_level) .append(msgDuplicatePackagePatternLocation, msg::path = location) - .append_raw("\n") + .append_raw('\n') .append_indent(indent_level) .append(msgDuplicatePackagePatternRegistry, msg::url = registry) - .append_raw("\n"); + .append_raw('\n'); } std::vector collect_package_pattern_warnings(const std::vector& registries) @@ -436,20 +436,20 @@ namespace auto first = locations.begin(); const auto last = locations.end(); auto warning = msg::format_warning(msgDuplicatePackagePattern, msg::package_name = pattern) - .append_raw("\n") + .append_raw('\n') .append_indent() .append(msgDuplicatePackagePatternFirstOcurrence) - .append_raw("\n"); + .append_raw('\n'); append_declaration_warning(warning, first->location, first->registry, 2) - .append_raw("\n") + .append_raw('\n') .append_indent() .append(msgDuplicatePackagePatternIgnoredLocations) - .append_raw("\n"); + .append_raw('\n'); ++first; append_declaration_warning(warning, first->location, first->registry, 2); while (++first != last) { - warning.append_raw("\n"); + warning.append_raw('\n'); append_declaration_warning(warning, first->location, first->registry, 2); } warnings.emplace_back(warning); diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index bf9d55bc36..92e91cb5ef 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -946,7 +946,7 @@ namespace vcpkg } else { - return msg::format(msgLinkageStaticRelease); + return msg::format(msgLinkageStaticDebug); } break; default: Checks::unreachable(VCPKG_LINE_INFO); @@ -1034,41 +1034,34 @@ namespace vcpkg { msg::println_warning(msgPortBugInvalidCrtLinkage, msg::expected = format_linkage(build_info.crt_linkage, expect_release)); + std::vector printed_linkages; for (const BuildTypeAndFile& btf : libs_with_invalid_crt) { - msg::print( - LocalizedString().append_indent().append(msgPortBugInvalidCrtLinkageEntry, msg::path = btf.file)); - LocalizedString prefix; - if ((btf.has_dynamic_debug + btf.has_dynamic_release + btf.has_static_debug + btf.has_static_release) == - 1) - { - prefix.append_raw(" "); - } - else - { - msg::println(); - prefix.append_indent(2); - } - + printed_linkages.clear(); + LocalizedString this_entry; + this_entry.append_indent().append(msgPortBugInvalidCrtLinkageEntry, msg::path = btf.file); if (btf.has_dynamic_debug) { - msg::println(LocalizedString(prefix).append(msgLinkageDynamicDebug)); + printed_linkages.push_back(msg::format(msgLinkageDynamicDebug)); } if (btf.has_dynamic_release) { - msg::println(LocalizedString(prefix).append(msgLinkageDynamicRelease)); + printed_linkages.push_back(msg::format(msgLinkageDynamicRelease)); } if (btf.has_static_debug) { - msg::println(LocalizedString(prefix).append(msgLinkageStaticDebug)); + printed_linkages.push_back(msg::format(msgLinkageStaticDebug)); } if (btf.has_static_release) { - msg::println(LocalizedString(prefix).append(msgLinkageStaticRelease)); + printed_linkages.push_back(msg::format(msgLinkageStaticRelease)); } + + this_entry.append_floating_list(2, printed_linkages); + msg::println(this_entry); } msg::println(msg::format(msgPortBugInspectFiles, msg::extension = "lib") diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index bb19873103..dba878254d 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -1210,16 +1210,16 @@ namespace vcpkg { LocalizedString ret; ret.append(msgFailedToParseConfig, msg::path = origin); - ret.append_raw("\n"); + ret.append_raw('\n'); for (auto&& err : reader.errors()) { ret.append_indent(); ret.append_fmt_raw("{}\n", err); } ret.append(msgExtendedDocumentationAtUrl, msg::url = docs::registries_url); - ret.append_raw("\n"); + ret.append_raw('\n'); ret.append(msgExtendedDocumentationAtUrl, msg::url = docs::manifests_url); - ret.append_raw("\n"); + ret.append_raw('\n'); return std::move(ret); } diff --git a/src/vcpkg/tools.cpp b/src/vcpkg/tools.cpp index 587d915976..5d14aa9f0d 100644 --- a/src/vcpkg/tools.cpp +++ b/src/vcpkg/tools.cpp @@ -212,7 +212,7 @@ namespace vcpkg virtual void add_system_package_info(LocalizedString& out) const { - out.append_raw(" ").append(msgInstallWithSystemManager); + out.append_raw(' ').append(msgInstallWithSystemManager); } }; @@ -419,11 +419,11 @@ namespace vcpkg virtual void add_system_package_info(LocalizedString& out) const override { #if defined(__APPLE__) - out.append_raw(" ").append(msgInstallWithSystemManagerPkg, msg::command_line = "brew install mono"); + out.append_raw(' ').append(msgInstallWithSystemManagerPkg, msg::command_line = "brew install mono"); #else - out.append_raw(" ").append(msgInstallWithSystemManagerPkg, + out.append_raw(' ').append(msgInstallWithSystemManagerPkg, msg::command_line = "sudo apt install mono-complete"); - out.append_raw(" ").append(msgInstallWithSystemManagerMono, + out.append_raw(' ').append(msgInstallWithSystemManagerMono, msg::url = "https://www.mono-project.com/download/stable/"); #endif } @@ -573,9 +573,9 @@ namespace vcpkg virtual void add_system_package_info(LocalizedString& out) const override { #if defined(__APPLE__) - out.append_raw(" ").append(msgInstallWithSystemManagerPkg, msg::command_line = "brew install python3"); + out.append_raw(' ').append(msgInstallWithSystemManagerPkg, msg::command_line = "brew install python3"); #else - out.append_raw(" ").append(msgInstallWithSystemManagerPkg, msg::command_line = "sudo apt install python3"); + out.append_raw(' ').append(msgInstallWithSystemManagerPkg, msg::command_line = "sudo apt install python3"); #endif } }; @@ -595,9 +595,9 @@ namespace vcpkg virtual void add_system_package_info(LocalizedString& out) const override { #if defined(__APPLE__) - out.append_raw(" ").append(msgInstallWithSystemManagerPkg, msg::command_line = "brew install python3"); + out.append_raw(' ').append(msgInstallWithSystemManagerPkg, msg::command_line = "brew install python3"); #else - out.append_raw(" ").append(msgInstallWithSystemManagerPkg, + out.append_raw(' ').append(msgInstallWithSystemManagerPkg, msg::command_line = "sudo apt install python3-virtualenv"); #endif } @@ -831,7 +831,7 @@ namespace vcpkg s.append(msgToolFetchFailed, msg::tool_name = tool.tool_data_name()); if (env_force_system_binaries && download_available) { - s.append_raw(" ").append(msgDownloadAvailable, msg::env_var = s_env_vcpkg_force_system_binaries); + s.append_raw(' ').append(msgDownloadAvailable, msg::env_var = s_env_vcpkg_force_system_binaries); } if (consider_system) { @@ -839,7 +839,7 @@ namespace vcpkg } else if (!download_available) { - s.append_raw(" ").append(msgUnknownTool); + s.append_raw(' ').append(msgUnknownTool); } Checks::msg_exit_maybe_upgrade(VCPKG_LINE_INFO, s); } From 9d3816b2d175ecff85a71d4bcd94e7d1917067be Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Tue, 7 Feb 2023 14:22:59 -0800 Subject: [PATCH 30/33] Append floating list typo Co-authored-by: Robert Schumacher --- src/vcpkg-test/messages.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vcpkg-test/messages.cpp b/src/vcpkg-test/messages.cpp index fd988ab0fe..2298e1e9ea 100644 --- a/src/vcpkg-test/messages.cpp +++ b/src/vcpkg-test/messages.cpp @@ -8,7 +8,7 @@ using namespace vcpkg; using namespace vcpkg::Commands; -TEST_CASE ("append floaging list", "[LocalizedString]") +TEST_CASE ("append floating list", "[LocalizedString]") { const auto a = LocalizedString::from_raw("a"); const auto b = LocalizedString::from_raw("b"); From c23af9392b35862d9e5997b6c8f122ef5d87a6e3 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Tue, 7 Feb 2023 14:27:49 -0800 Subject: [PATCH 31/33] Defer the string concat to when debug is on., Co-authored-by: Robert Schumacher --- src/vcpkg/postbuildlint.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index 92e91cb5ef..fc17653f19 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -970,8 +970,8 @@ namespace vcpkg } auto&& lib_info = maybe_lib_info.value_or_exit(VCPKG_LINE_INFO); - Debug::println("The lib " + lib.native() + - " has directives: " + Strings::join(" ", lib_info.linker_directives)); + Debug::println("The lib ", lib.native(), + " has directives: ", Strings::join(" ", lib_info.linker_directives)); BuildTypeAndFile this_lib{lib}; constexpr static const StringLiteral static_release_crt = "/DEFAULTLIB:LIBCMT"; From b5aba78a793283363b9910d437bc0205df0f70a0 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 7 Feb 2023 14:18:51 -0800 Subject: [PATCH 32/33] Introduce try_read_all_from which combines the seek and read operations. --- include/vcpkg/base/files.h | 1 + src/vcpkg/base/cofffilereader.cpp | 41 ++++--------------------------- src/vcpkg/base/files.cpp | 5 ++++ 3 files changed, 11 insertions(+), 36 deletions(-) diff --git a/include/vcpkg/base/files.h b/include/vcpkg/base/files.h index 2a2f4d81bd..bd852295d1 100644 --- a/include/vcpkg/base/files.h +++ b/include/vcpkg/base/files.h @@ -137,6 +137,7 @@ namespace vcpkg size_t read(void* buffer, size_t element_size, size_t element_count) const noexcept; ExpectedL try_read_all(void* buffer, std::uint32_t size); ExpectedL try_getc(); + ExpectedL try_read_all_from(long long offset, void* buffer, std::uint32_t size); }; struct WriteFilePointer : FilePointer diff --git a/src/vcpkg/base/cofffilereader.cpp b/src/vcpkg/base/cofffilereader.cpp index 30fb36fd61..0234dd7d09 100644 --- a/src/vcpkg/base/cofffilereader.cpp +++ b/src/vcpkg/base/cofffilereader.cpp @@ -28,34 +28,18 @@ namespace static constexpr long OFFSET_TO_PE_SIGNATURE_OFFSET = 0x3c; static constexpr StringLiteral PE_SIGNATURE = "PE\0\0"; static constexpr auto PE_SIGNATURE_SIZE = static_cast(PE_SIGNATURE.size()); - { - auto seek_to_signature_offset = f.try_seek_to(OFFSET_TO_PE_SIGNATURE_OFFSET); - if (!seek_to_signature_offset.has_value()) - { - return std::move(seek_to_signature_offset).error(); - } - } - uint32_t offset; { - auto read_offset = f.try_read_all(&offset, sizeof(offset)); + auto read_offset = f.try_read_all_from(OFFSET_TO_PE_SIGNATURE_OFFSET, &offset, sizeof(offset)); if (!read_offset.has_value()) { return std::move(read_offset).error(); } } - { - auto seek_to_signature = f.try_seek_to(offset); - if (!seek_to_signature.has_value()) - { - return std::move(seek_to_signature).error(); - } - } - char signature[PE_SIGNATURE_SIZE]; { - auto read_signature = f.try_read_all(signature, PE_SIGNATURE_SIZE); + auto read_signature = f.try_read_all_from(offset, signature, PE_SIGNATURE_SIZE); if (!read_signature.has_value()) { return std::move(read_signature).error(); @@ -424,17 +408,9 @@ namespace { // Skip the header, no need to read it const auto coff_base = offset + sizeof(ArchiveMemberHeader); - { - auto seek = f.try_seek_to(coff_base); - if (!seek.has_value()) - { - return std::move(seek).error(); - } - } - uint32_t tag_sniffer; { - auto read = f.try_read_all(&tag_sniffer, sizeof(tag_sniffer)); + auto read = f.try_read_all_from(coff_base, &tag_sniffer, sizeof(tag_sniffer)); if (!read.has_value()) { return std::move(read).error(); @@ -511,17 +487,10 @@ namespace // read the actual directive std::string directive_command_line; const auto section_offset = coff_base + section.pointer_to_raw_data; - { - auto seek = f.try_seek_to(section_offset); - if (!seek.has_value()) - { - return std::move(seek).error(); - } - } - directive_command_line.resize(section.size_of_raw_data); { - auto read = f.try_read_all(directive_command_line.data(), section.size_of_raw_data); + auto read = f.try_read_all_from( + section_offset, directive_command_line.data(), section.size_of_raw_data); if (!read.has_value()) { return std::move(read).error(); diff --git a/src/vcpkg/base/files.cpp b/src/vcpkg/base/files.cpp index 1fa0a797e4..005469a807 100644 --- a/src/vcpkg/base/files.cpp +++ b/src/vcpkg/base/files.cpp @@ -1464,6 +1464,11 @@ namespace vcpkg return static_cast(result); } + ExpectedL ReadFilePointer::try_read_all_from(long long offset, void* buffer, std::uint32_t size) + { + return try_seek_to(offset).then([&](Unit) { return try_read_all(buffer, size); }); + } + WriteFilePointer::WriteFilePointer() noexcept = default; WriteFilePointer::WriteFilePointer(WriteFilePointer&&) noexcept = default; From 125f5c9a6c1695d3754a915ad3f47344847a1a83 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 7 Feb 2023 14:37:42 -0800 Subject: [PATCH 33/33] Report dll load errors as errors. --- src/vcpkg/postbuildlint.cpp | 61 ++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index fc17653f19..de5adfe0f9 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -434,8 +434,14 @@ namespace vcpkg return std::move(maybe_metadata).error(); } - bool has_exports = try_read_if_dll_has_exports(*metadata, *file).value_or(true); + auto maybe_has_exports = try_read_if_dll_has_exports(*metadata, *file); + auto phas_exports = maybe_has_exports.get(); + if (!phas_exports) + { + return std::move(maybe_has_exports).error(); + } + bool has_exports = *phas_exports; bool has_appcontainer; switch (metadata->pe_type) { @@ -970,8 +976,8 @@ namespace vcpkg } auto&& lib_info = maybe_lib_info.value_or_exit(VCPKG_LINE_INFO); - Debug::println("The lib ", lib.native(), - " has directives: ", Strings::join(" ", lib_info.linker_directives)); + Debug::println( + "The lib ", lib.native(), " has directives: ", Strings::join(" ", lib_info.linker_directives)); BuildTypeAndFile this_lib{lib}; constexpr static const StringLiteral static_release_crt = "/DEFAULTLIB:LIBCMT"; @@ -1229,6 +1235,28 @@ namespace vcpkg static void operator+=(size_t& left, const LintStatus& right) { left += static_cast(right); } + static size_t perform_post_build_checks_dll_loads(const Filesystem& fs, + std::vector& dlls, + const std::vector& dll_files) + { + size_t error_count = 0; + for (const Path& dll : dll_files) + { + auto maybe_dll_data = try_load_dll_data(fs, dll); + if (const auto dll_data = maybe_dll_data.get()) + { + dlls.emplace_back(std::move(*dll_data)); + } + else + { + ++error_count; + msg::println(Color::warning, maybe_dll_data.error()); + } + } + + return error_count; + } + static size_t perform_all_checks_and_return_error_count(const PackageSpec& spec, const VcpkgPaths& paths, const PreBuildInfo& pre_build_info, @@ -1318,24 +1346,8 @@ namespace vcpkg std::vector dlls; dlls.reserve(debug_dlls.size() + release_dlls.size()); - for (const Path& dll : debug_dlls) - { - auto maybe_dll_data = try_load_dll_data(fs, dll); - if (const auto dll_data = maybe_dll_data.get()) - { - dlls.emplace_back(std::move(*dll_data)); - } - } - - for (const Path& dll : release_dlls) - { - auto maybe_dll_data = try_load_dll_data(fs, dll); - if (const auto dll_data = maybe_dll_data.get()) - { - dlls.emplace_back(std::move(*dll_data)); - } - } - + error_count += perform_post_build_checks_dll_loads(fs, dlls, debug_dlls); + error_count += perform_post_build_checks_dll_loads(fs, dlls, release_dlls); error_count += check_exports_of_dlls(build_info.policies, dlls); error_count += check_uwp_bit_of_dlls(pre_build_info.cmake_system_name, dlls); error_count += check_outdated_crt_linkage_of_dlls(dlls, build_info, pre_build_info); @@ -1347,10 +1359,11 @@ namespace vcpkg break; case LinkageType::STATIC: { - auto dlls = release_dlls; - dlls.insert(dlls.end(), debug_dlls.begin(), debug_dlls.end()); + auto& dlls = debug_dlls; + dlls.insert(dlls.end(), + std::make_move_iterator(release_dlls.begin()), + std::make_move_iterator(release_dlls.end())); error_count += check_no_dlls_present(build_info.policies, dlls); - error_count += check_bin_folders_are_not_present_in_static_build(build_info.policies, fs, package_dir); if (!build_info.policies.is_enabled(BuildPolicy::ONLY_RELEASE_CRT))