From 89447c156d3b99ba63499aa4b8f23b985ccd6474 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Wed, 9 Nov 2016 01:27:49 -0800 Subject: [PATCH] Add checks for crt linkage (currently disabled) --- toolsrc/include/BuildInfo.h | 36 ++++++++++ toolsrc/src/BuildInfo.cpp | 72 ++++++++++++++++++++ toolsrc/src/post_build_lint.cpp | 116 ++++++++++++++++++++++++++++++++ 3 files changed, 224 insertions(+) diff --git a/toolsrc/include/BuildInfo.h b/toolsrc/include/BuildInfo.h index 2801cf49d..870001474 100644 --- a/toolsrc/include/BuildInfo.h +++ b/toolsrc/include/BuildInfo.h @@ -16,6 +16,42 @@ namespace vcpkg LinkageType linkage_type_value_of(const std::string& as_string); + std::string to_string(const LinkageType& build_info); + + enum class ConfigurationType + { + DEBUG = 1, + RELEASE = 2 + }; + + std::string to_string(const ConfigurationType& conf); + + struct BuildType + { + static BuildType value_of(const ConfigurationType& config, const LinkageType& linkage); + + static const BuildType DEBUG_STATIC; + static const BuildType DEBUG_DYNAMIC; + static const BuildType RELEASE_STATIC; + static const BuildType RELEASE_DYNAMIC; + + const ConfigurationType config; + const LinkageType linkage; + + BuildType() = delete; + + std::string toString() const; + + private: + BuildType(const ConfigurationType& config, const LinkageType& linkage) : config(config), linkage(linkage) + { + } + }; + + bool operator ==(const BuildType& lhs, const BuildType& rhs); + + bool operator !=(const BuildType& lhs, const BuildType& rhs); + struct BuildInfo { static BuildInfo create(const std::unordered_map& pgh); diff --git a/toolsrc/src/BuildInfo.cpp b/toolsrc/src/BuildInfo.cpp index dc8d90e2e..2e74eefc3 100644 --- a/toolsrc/src/BuildInfo.cpp +++ b/toolsrc/src/BuildInfo.cpp @@ -4,6 +4,21 @@ namespace vcpkg { + std::string BuildType::toString() const + { + return Strings::format("[%s,%s]", to_string(config), to_string(linkage)); + } + + bool operator==(const BuildType& lhs, const BuildType& rhs) + { + return lhs.config == rhs.config && lhs.linkage == rhs.linkage; + } + + bool operator!=(const BuildType& lhs, const BuildType& rhs) + { + return !(lhs == rhs); + } + // namespace BuildInfoRequiredField { @@ -20,6 +35,11 @@ namespace vcpkg return build_info; } + const BuildType BuildType::DEBUG_STATIC = BuildType(ConfigurationType::DEBUG, LinkageType::STATIC); + const BuildType BuildType::DEBUG_DYNAMIC = BuildType(ConfigurationType::DEBUG, LinkageType::DYNAMIC); + const BuildType BuildType::RELEASE_STATIC = BuildType(ConfigurationType::RELEASE, LinkageType::STATIC); + const BuildType BuildType::RELEASE_DYNAMIC = BuildType(ConfigurationType::RELEASE, LinkageType::DYNAMIC); + LinkageType linkage_type_value_of(const std::string& as_string) { @@ -36,6 +56,58 @@ namespace vcpkg return LinkageType::UNKNOWN; } + std::string to_string(const LinkageType& build_info) + { + switch (build_info) + { + case LinkageType::STATIC: + return "static"; + case LinkageType::DYNAMIC: + return "dynamic"; + default: + Checks::unreachable(); + } + } + + std::string to_string(const ConfigurationType& conf) + + { + switch (conf) + { + case ConfigurationType::DEBUG: + return "Debug"; + case ConfigurationType::RELEASE: + return "Release"; + default: + Checks::unreachable(); + } + } + + BuildType BuildType::value_of(const ConfigurationType& config, const LinkageType& linkage) + { + if (config == ConfigurationType::DEBUG && linkage == LinkageType::STATIC) + { + return DEBUG_STATIC; + } + + if (config == ConfigurationType::DEBUG && linkage == LinkageType::DYNAMIC) + { + return DEBUG_DYNAMIC; + } + + if (config == ConfigurationType::RELEASE && linkage == LinkageType::STATIC) + { + return RELEASE_STATIC; + } + + if (config == ConfigurationType::RELEASE && linkage == LinkageType::DYNAMIC) + { + return RELEASE_DYNAMIC; + } + + Checks::unreachable(); + } + BuildInfo read_build_info(const fs::path& filepath) { const std::vector> pghs = Paragraphs::get_paragraphs(filepath); diff --git a/toolsrc/src/post_build_lint.cpp b/toolsrc/src/post_build_lint.cpp index 634e85c05..9cd88bff1 100644 --- a/toolsrc/src/post_build_lint.cpp +++ b/toolsrc/src/post_build_lint.cpp @@ -6,6 +6,7 @@ #include "vcpkg_System.h" #include "coff_file_reader.h" #include "BuildInfo.h" +#include namespace fs = std::tr2::sys; @@ -488,6 +489,116 @@ namespace vcpkg return lint_status::SUCCESS; } + struct BuildInfo_and_files + { + explicit BuildInfo_and_files(const BuildType& build_type) : build_type(build_type) + { + } + + BuildType build_type; + std::vector files; + }; + + static lint_status check_crt_linkage_of_libs(const BuildType& expected_build_type, const std::vector& libs) + { + static const std::regex DEBUG_STATIC_CRT(R"(/DEFAULTLIB:LIBCMTD)"); + static const std::regex DEBUG_DYNAMIC_CRT(R"(/DEFAULTLIB:MSVCRTD)"); + + static const std::regex RELEASE_STATIC_CRT(R"(/DEFAULTLIB:LIBCMT[^D])"); + static const std::regex RELEASE_DYNAMIC_CRT(R"(/DEFAULTLIB:MSVCRT[^D])"); + + lint_status output_status = lint_status::SUCCESS; + + std::vector libs_with_no_crts; + std::vector libs_with_multiple_crts; + + BuildInfo_and_files libs_with_debug_static_crt(BuildType::DEBUG_STATIC); + BuildInfo_and_files libs_with_debug_dynamic_crt(BuildType::DEBUG_DYNAMIC); + BuildInfo_and_files libs_with_release_static_crt(BuildType::RELEASE_STATIC); + BuildInfo_and_files libs_with_release_dynamic_crt(BuildType::RELEASE_DYNAMIC); + + for (const fs::path& lib : libs) + { + const std::wstring cmd_line = Strings::wformat(LR"("%s" /directives "%s")", DUMPBIN_EXE.native(), lib.native()); + System::exit_code_and_output ec_data = System::cmd_execute_and_capture_output(cmd_line); + Checks::check_exit(ec_data.exit_code == 0, "Running command:\n %s\n failed", Strings::utf16_to_utf8(cmd_line)); + + bool found_debug_static_crt = std::regex_search(ec_data.output.cbegin(), ec_data.output.cend(), DEBUG_STATIC_CRT); + bool found_debug_dynamic_crt = std::regex_search(ec_data.output.cbegin(), ec_data.output.cend(), DEBUG_DYNAMIC_CRT); + bool found_release_static_crt = std::regex_search(ec_data.output.cbegin(), ec_data.output.cend(), RELEASE_STATIC_CRT); + bool found_release_dynamic_crt = std::regex_search(ec_data.output.cbegin(), ec_data.output.cend(), RELEASE_DYNAMIC_CRT); + + const size_t crts_found_count = found_debug_static_crt + found_debug_dynamic_crt + found_release_static_crt + found_release_dynamic_crt; + + if (crts_found_count == 0) + { + libs_with_no_crts.push_back(lib); + continue; + } + + if (crts_found_count > 1) + { + libs_with_multiple_crts.push_back(lib); + continue; + } + + // now we have exactly 1 crt + if (found_debug_static_crt) + { + libs_with_debug_static_crt.files.push_back(lib); + continue; + } + if (found_debug_dynamic_crt) + { + libs_with_debug_dynamic_crt.files.push_back(lib); + continue; + } + + if (found_release_static_crt) + { + libs_with_release_static_crt.files.push_back(lib); + continue; + } + + libs_with_release_dynamic_crt.files.push_back(lib); + } + + if (!libs_with_no_crts.empty()) + { + System::println(System::color::warning, "Could not detect the crt linkage in the following libs:"); + print_vector_of_files(libs_with_no_crts); + output_status = lint_status::ERROR_DETECTED; + } + + if (!libs_with_multiple_crts.empty()) + { + System::println(System::color::warning, "Detected multiple crt linkages for the following libs:"); + print_vector_of_files(libs_with_multiple_crts); + output_status = lint_status::ERROR_DETECTED; + } + + std::vector group_for_iteration = { + libs_with_debug_static_crt, libs_with_debug_dynamic_crt, + libs_with_release_static_crt, libs_with_release_dynamic_crt}; + + for (const BuildInfo_and_files& bif : group_for_iteration) + { + if (!bif.files.empty() && bif.build_type != expected_build_type) + { + System::println(System::color::warning, "Expected %s crt linkage, but the following libs had %s crt linkage:", expected_build_type.toString(), bif.build_type.toString()); + print_vector_of_files(bif.files); + output_status = lint_status::ERROR_DETECTED; + } + } + + if (output_status == lint_status::ERROR_DETECTED) + { + System::println(System::color::warning, "To inspect the lib files, use:\n dumpbin.exe /directives mylibfile.lib"); + } + + return output_status; + } + static void operator +=(size_t& left, const lint_status& right) { left += static_cast(right); @@ -546,6 +657,11 @@ namespace vcpkg error_count += check_no_dlls_present(dlls); error_count += check_bin_folders_are_not_present_in_static_build(spec, paths); + +#if 0 + error_count += check_crt_linkage_of_libs(BuildType::value_of(ConfigurationType::DEBUG, linkage_type_value_of(build_info.crt_linkage)), debug_libs); + error_count += check_crt_linkage_of_libs(BuildType::value_of(ConfigurationType::RELEASE, linkage_type_value_of(build_info.crt_linkage)), release_libs); +#endif break; } case LinkageType::UNKNOWN: