vcpkg/toolsrc/src/PostBuildLint.cpp

728 lines
31 KiB
C++
Raw Normal View History

2017-01-28 04:49:09 +08:00
#include "pch.h"
2016-09-19 11:50:08 +08:00
#include "vcpkg_paths.h"
2017-04-04 05:45:00 +08:00
#include "PackageSpec.h"
2016-11-30 09:04:41 +08:00
#include "vcpkg_Files.h"
2016-09-19 11:50:08 +08:00
#include "vcpkg_System.h"
#include "coff_file_reader.h"
#include "PostBuildLint_BuildInfo.h"
#include "PostBuildLint_BuildType.h"
#include "PostBuildLint.h"
2016-09-19 11:50:08 +08:00
2017-01-06 06:14:11 +08:00
namespace vcpkg::PostBuildLint
2016-09-19 11:50:08 +08:00
{
enum class lint_status
{
SUCCESS = 0,
ERROR_DETECTED = 1
2016-09-19 11:50:08 +08:00
};
struct OutdatedDynamicCrt
{
std::string name;
std::regex regex;
OutdatedDynamicCrt(const std::string& name, const std::string& regex_as_string)
2017-02-09 08:13:27 +08:00
: name(name),
regex(std::regex(regex_as_string, std::regex_constants::icase)) {}
};
const std::vector<OutdatedDynamicCrt>& get_outdated_dynamic_crts()
{
static const std::vector<OutdatedDynamicCrt> v = {
2017-03-04 10:42:57 +08:00
{ "msvcp100.dll", R"(msvcp100\.dll)" },
{ "msvcp100d.dll", R"(msvcp100d\.dll)" },
{ "msvcp110.dll", R"(msvcp110\.dll)" },
{ "msvcp110_win.dll", R"(msvcp110_win\.dll)" },
{ "msvcp120.dll", R"(msvcp120\.dll)" },
{ "msvcp120_clr0400.dll", R"(msvcp120_clr0400\.dll)" },
{ "msvcp60.dll", R"(msvcp60\.dll)" },
{ "msvcp60.dll", R"(msvcp60\.dll)" },
{ "msvcr100.dll", R"(msvcr100\.dll)" },
{ "msvcr100d.dll", R"(msvcr100d\.dll)" },
{ "msvcr100_clr0400.dll", R"(msvcr100_clr0400\.dll)" },
{ "msvcr110.dll", R"(msvcr110\.dll)" },
{ "msvcr120.dll", R"(msvcr120\.dll)" },
{ "msvcr120_clr0400.dll", R"(msvcr120_clr0400\.dll)" },
{ "msvcrt.dll", R"(msvcrt\.dll)" },
{ "msvcrt20.dll", R"(msvcrt20\.dll)" },
{ "msvcrt40.dll", R"(msvcrt40\.dll)" }
};
return v;
}
template <class T>
2017-04-04 05:43:44 +08:00
static bool contains_and_enabled(const std::map<T, OptBoolT> map, const T& key)
{
auto it = map.find(key);
2017-04-04 05:43:44 +08:00
if (it != map.cend() && it->second == OptBoolT::ENABLED)
{
return true;
}
return false;
}
2017-04-04 05:43:44 +08:00
static lint_status check_for_files_in_include_directory(const std::map<BuildPolicies::type, OptBoolT>& policies, const fs::path& package_dir)
2016-09-19 11:50:08 +08:00
{
if (contains_and_enabled(policies, BuildPolicies::EMPTY_INCLUDE_FOLDER))
{
return lint_status::SUCCESS;
}
const fs::path include_dir = package_dir / "include";
2016-09-19 11:50:08 +08:00
if (!fs::exists(include_dir) || fs::is_empty(include_dir))
{
System::println(System::color::warning, "The folder /include is empty. This indicates the library was not correctly installed.");
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
return lint_status::SUCCESS;
}
static lint_status check_for_files_in_debug_include_directory(const fs::path& package_dir)
2016-09-19 11:50:08 +08:00
{
const fs::path debug_include_dir = package_dir / "debug" / "include";
2016-09-19 11:50:08 +08:00
std::vector<fs::path> files_found;
2016-11-30 09:04:41 +08:00
Files::recursive_find_matching_paths_in_dir(debug_include_dir, [&](const fs::path& current)
{
return !fs::is_directory(current) && current.extension() != ".ifc";
}, &files_found);
2016-09-19 11:50:08 +08:00
if (!files_found.empty())
{
System::println(System::color::warning, "Include files should not be duplicated into the /debug/include directory. If this cannot be disabled in the project cmake, use\n"
" file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/include)"
);
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
2016-09-29 06:34:10 +08:00
return lint_status::SUCCESS;
2016-09-19 11:50:08 +08:00
}
static lint_status check_for_files_in_debug_share_directory(const fs::path& package_dir)
2016-09-19 11:50:08 +08:00
{
const fs::path debug_share = package_dir / "debug" / "share";
2016-09-19 11:50:08 +08:00
if (fs::exists(debug_share) && !fs::is_empty(debug_share))
{
System::println(System::color::warning, "/debug/share should not exist. Please reorganize any important files, then use\n"
" file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/share)");
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
return lint_status::SUCCESS;
}
2017-04-04 05:45:00 +08:00
static lint_status check_folder_lib_cmake(const fs::path& package_dir, const PackageSpec& spec)
2016-09-19 11:50:08 +08:00
{
const fs::path lib_cmake = package_dir / "lib" / "cmake";
2016-09-19 11:50:08 +08:00
if (fs::exists(lib_cmake))
{
System::println(System::color::warning, "The /lib/cmake folder should be moved to /share/%s/cmake.", spec.name());
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
return lint_status::SUCCESS;
}
2017-04-04 05:45:00 +08:00
static lint_status check_for_misplaced_cmake_files(const fs::path& package_dir, const PackageSpec& spec)
2016-09-19 11:50:08 +08:00
{
std::vector<fs::path> misplaced_cmake_files;
2016-11-30 09:04:41 +08:00
Files::recursive_find_files_with_extension_in_dir(package_dir / "cmake", ".cmake", &misplaced_cmake_files);
Files::recursive_find_files_with_extension_in_dir(package_dir / "debug" / "cmake", ".cmake", &misplaced_cmake_files);
Files::recursive_find_files_with_extension_in_dir(package_dir / "lib" / "cmake", ".cmake", &misplaced_cmake_files);
Files::recursive_find_files_with_extension_in_dir(package_dir / "debug" / "lib" / "cmake", ".cmake", &misplaced_cmake_files);
2016-09-19 11:50:08 +08:00
if (!misplaced_cmake_files.empty())
{
System::println(System::color::warning, "The following cmake files were found outside /share/%s. Please place cmake files in /share/%s.", spec.name(), spec.name());
2016-12-01 06:08:43 +08:00
Files::print_paths(misplaced_cmake_files);
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
return lint_status::SUCCESS;
}
static lint_status check_folder_debug_lib_cmake(const fs::path& package_dir)
2016-09-19 11:50:08 +08:00
{
const fs::path lib_cmake_debug = package_dir / "debug" / "lib" / "cmake";
2016-09-19 11:50:08 +08:00
if (fs::exists(lib_cmake_debug))
{
System::println(System::color::warning, "The /debug/lib/cmake folder should be moved to just /debug/cmake");
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
return lint_status::SUCCESS;
}
static lint_status check_for_dlls_in_lib_dirs(const fs::path& package_dir)
2016-09-19 11:50:08 +08:00
{
std::vector<fs::path> dlls;
2016-11-30 09:04:41 +08:00
Files::recursive_find_files_with_extension_in_dir(package_dir / "lib", ".dll", &dlls);
Files::recursive_find_files_with_extension_in_dir(package_dir / "debug" / "lib", ".dll", &dlls);
2016-09-19 11:50:08 +08:00
if (!dlls.empty())
{
System::println(System::color::warning, "\nThe following dlls were found in /lib and /debug/lib. Please move them to /bin or /debug/bin, respectively.");
2016-12-01 06:08:43 +08:00
Files::print_paths(dlls);
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
return lint_status::SUCCESS;
}
2017-04-04 05:45:00 +08:00
static lint_status check_for_copyright_file(const PackageSpec& spec, const vcpkg_paths& paths)
2016-09-19 11:50:08 +08:00
{
const fs::path packages_dir = paths.packages / spec.dir();
const fs::path copyright_file = packages_dir / "share" / spec.name() / "copyright";
2016-09-19 11:50:08 +08:00
if (fs::exists(copyright_file))
{
return lint_status::SUCCESS;
}
const fs::path current_buildtrees_dir = paths.buildtrees / spec.name();
2016-09-19 11:50:08 +08:00
const fs::path current_buildtrees_dir_src = current_buildtrees_dir / "src";
std::vector<fs::path> potential_copyright_files;
// Only searching one level deep
for (auto it = fs::recursive_directory_iterator(current_buildtrees_dir_src); it != fs::recursive_directory_iterator(); ++it)
{
if (it.depth() > 1)
{
continue;
}
const std::string filename = it->path().filename().string();
if (filename == "LICENSE" || filename == "LICENSE.txt" || filename == "COPYING")
{
potential_copyright_files.push_back(it->path());
}
}
System::println(System::color::warning, "The software license must be available at ${CURRENT_PACKAGES_DIR}/share/%s/copyright .", spec.name());
2016-09-19 11:50:08 +08:00
if (potential_copyright_files.size() == 1) // if there is only one candidate, provide the cmake lines needed to place it in the proper location
{
const fs::path found_file = potential_copyright_files[0];
const fs::path relative_path = found_file.string().erase(0, current_buildtrees_dir.string().size() + 1); // The +1 is needed to remove the "/"
System::println("\n file(COPY ${CURRENT_BUILDTREES_DIR}/%s DESTINATION ${CURRENT_PACKAGES_DIR}/share/%s)\n"
" file(RENAME ${CURRENT_PACKAGES_DIR}/share/%s/%s ${CURRENT_PACKAGES_DIR}/share/%s/copyright)",
relative_path.generic_string(), spec.name(), spec.name(), found_file.filename().generic_string(), spec.name());
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
if (potential_copyright_files.size() > 1)
{
System::println(System::color::warning, "The following files are potential copyright files:");
2016-12-01 06:08:43 +08:00
Files::print_paths(potential_copyright_files);
2016-09-19 11:50:08 +08:00
}
System::println(" %s/share/%s/copyright", packages_dir.generic_string(), spec.name());
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
static lint_status check_for_exes(const fs::path& package_dir)
2016-09-19 11:50:08 +08:00
{
std::vector<fs::path> exes;
2016-11-30 09:04:41 +08:00
Files::recursive_find_files_with_extension_in_dir(package_dir / "bin", ".exe", &exes);
Files::recursive_find_files_with_extension_in_dir(package_dir / "debug" / "bin", ".exe", &exes);
2016-09-19 11:50:08 +08:00
if (!exes.empty())
{
System::println(System::color::warning, "The following EXEs were found in /bin and /debug/bin. EXEs are not valid distribution targets.");
2016-12-01 06:08:43 +08:00
Files::print_paths(exes);
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
return lint_status::SUCCESS;
}
static lint_status check_exports_of_dlls(const std::vector<fs::path>& dlls, const fs::path& dumpbin_exe)
2016-09-19 11:50:08 +08:00
{
std::vector<fs::path> dlls_with_no_exports;
for (const fs::path& dll : dlls)
{
const std::wstring cmd_line = Strings::wformat(LR"("%s" /exports "%s")", dumpbin_exe.native(), dll.native());
2016-09-19 11:50:08 +08:00
System::exit_code_and_output ec_data = System::cmd_execute_and_capture_output(cmd_line);
Checks::check_exit(VCPKG_LINE_INFO, ec_data.exit_code == 0, "Running command:\n %s\n failed", Strings::utf16_to_utf8(cmd_line));
2016-09-19 11:50:08 +08:00
if (ec_data.output.find("ordinal hint RVA name") == std::string::npos)
{
dlls_with_no_exports.push_back(dll);
}
}
if (!dlls_with_no_exports.empty())
{
System::println(System::color::warning, "The following DLLs have no exports:");
2016-12-01 06:08:43 +08:00
Files::print_paths(dlls_with_no_exports);
2016-09-19 11:50:08 +08:00
System::println(System::color::warning, "DLLs without any exports are likely a bug in the build script.");
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
return lint_status::SUCCESS;
}
static lint_status check_uwp_bit_of_dlls(const std::string& expected_system_name, const std::vector<fs::path>& dlls, const fs::path dumpbin_exe)
2016-09-19 11:50:08 +08:00
{
if (expected_system_name != "uwp")
{
return lint_status::SUCCESS;
}
std::vector<fs::path> dlls_with_improper_uwp_bit;
for (const fs::path& dll : dlls)
{
const std::wstring cmd_line = Strings::wformat(LR"("%s" /headers "%s")", dumpbin_exe.native(), dll.native());
2016-09-19 11:50:08 +08:00
System::exit_code_and_output ec_data = System::cmd_execute_and_capture_output(cmd_line);
Checks::check_exit(VCPKG_LINE_INFO, ec_data.exit_code == 0, "Running command:\n %s\n failed", Strings::utf16_to_utf8(cmd_line));
2016-09-19 11:50:08 +08:00
if (ec_data.output.find("App Container") == std::string::npos)
{
dlls_with_improper_uwp_bit.push_back(dll);
}
}
if (!dlls_with_improper_uwp_bit.empty())
{
System::println(System::color::warning, "The following DLLs do not have the App Container bit set:");
2016-12-01 06:08:43 +08:00
Files::print_paths(dlls_with_improper_uwp_bit);
2016-09-19 11:50:08 +08:00
System::println(System::color::warning, "This bit is required for Windows Store apps.");
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
return lint_status::SUCCESS;
}
struct file_and_arch
{
fs::path file;
std::string actual_arch;
};
static std::string get_actual_architecture(const MachineType& machine_type)
2016-09-19 11:50:08 +08:00
{
switch (machine_type)
{
case MachineType::AMD64:
case MachineType::IA64:
return "x64";
case MachineType::I386:
return "x86";
case MachineType::ARM:
case MachineType::ARMNT:
return "arm";
default:
return "Machine Type Code = " + std::to_string(static_cast<uint16_t>(machine_type));
}
}
static void print_invalid_architecture_files(const std::string& expected_architecture, std::vector<file_and_arch> binaries_with_invalid_architecture)
{
System::println(System::color::warning, "The following files were built for an incorrect architecture:");
System::println("");
for (const file_and_arch& b : binaries_with_invalid_architecture)
{
System::println(" %s", b.file.generic_string());
System::println("Expected %s, but was: %s", expected_architecture, b.actual_arch);
System::println("");
}
}
static lint_status check_dll_architecture(const std::string& expected_architecture, const std::vector<fs::path>& files)
{
2016-09-19 11:50:08 +08:00
std::vector<file_and_arch> binaries_with_invalid_architecture;
for (const fs::path& file : files)
2016-09-19 11:50:08 +08:00
{
Checks::check_exit(VCPKG_LINE_INFO, file.extension() == ".dll", "The file extension was not .dll: %s", file.generic_string());
2017-04-04 05:19:13 +08:00
COFFFileReader::DllInfo info = COFFFileReader::read_dll(file);
const std::string actual_architecture = get_actual_architecture(info.machine_type);
if (expected_architecture != actual_architecture)
2016-09-19 11:50:08 +08:00
{
2017-03-04 10:42:57 +08:00
binaries_with_invalid_architecture.push_back({ file, actual_architecture });
2016-09-19 11:50:08 +08:00
}
}
if (!binaries_with_invalid_architecture.empty())
{
print_invalid_architecture_files(expected_architecture, binaries_with_invalid_architecture);
return lint_status::ERROR_DETECTED;
}
return lint_status::SUCCESS;
}
static lint_status check_lib_architecture(const std::string& expected_architecture, const std::vector<fs::path>& files)
{
std::vector<file_and_arch> binaries_with_invalid_architecture;
for (const fs::path& file : files)
{
Checks::check_exit(VCPKG_LINE_INFO, file.extension() == ".lib", "The file extension was not .lib: %s", file.generic_string());
2017-04-04 05:19:13 +08:00
COFFFileReader::LibInfo info = COFFFileReader::read_lib(file);
Checks::check_exit(VCPKG_LINE_INFO, info.machine_types.size() == 1, "Found more than 1 architecture in file %s", file.generic_string());
const std::string actual_architecture = get_actual_architecture(info.machine_types.at(0));
if (expected_architecture != actual_architecture)
{
2017-03-04 10:42:57 +08:00
binaries_with_invalid_architecture.push_back({ file, actual_architecture });
2016-09-19 11:50:08 +08:00
}
}
2016-09-19 11:50:08 +08:00
if (!binaries_with_invalid_architecture.empty())
{
print_invalid_architecture_files(expected_architecture, binaries_with_invalid_architecture);
return lint_status::ERROR_DETECTED;
2016-09-19 11:50:08 +08:00
}
return lint_status::SUCCESS;
}
static lint_status check_no_dlls_present(const std::vector<fs::path>& dlls)
{
if (dlls.empty())
{
return lint_status::SUCCESS;
}
System::println(System::color::warning, "DLLs should not be present in a static build, but the following DLLs were found:");
2016-12-01 06:08:43 +08:00
Files::print_paths(dlls);
return lint_status::ERROR_DETECTED;
}
static lint_status check_matching_debug_and_release_binaries(const std::vector<fs::path>& debug_binaries, const std::vector<fs::path>& release_binaries)
{
const size_t debug_count = debug_binaries.size();
const size_t release_count = release_binaries.size();
if (debug_count == release_count)
{
return lint_status::SUCCESS;
}
System::println(System::color::warning, "Mismatching number of debug and release binaries. Found %d for debug but %d for release.", debug_count, release_count);
System::println("Debug binaries");
2016-12-01 06:08:43 +08:00
Files::print_paths(debug_binaries);
System::println("Release binaries");
2016-12-01 06:08:43 +08:00
Files::print_paths(release_binaries);
if (debug_count == 0)
{
System::println(System::color::warning, "Debug binaries were not found");
}
if (release_count == 0)
{
System::println(System::color::warning, "Release binaries were not found");
}
System::println("");
return lint_status::ERROR_DETECTED;
}
2017-04-04 05:43:44 +08:00
static lint_status check_lib_files_are_available_if_dlls_are_available(const std::map<BuildPolicies::type, OptBoolT>& policies, const size_t lib_count, const size_t dll_count, const fs::path& lib_dir)
{
2017-02-01 10:31:19 +08:00
auto it = policies.find(BuildPolicies::DLLS_WITHOUT_LIBS);
2017-04-04 05:43:44 +08:00
if (it != policies.cend() && it->second == OptBoolT::ENABLED)
2017-02-01 10:31:19 +08:00
{
return lint_status::SUCCESS;
}
if (lib_count == 0 && dll_count != 0)
{
System::println(System::color::warning, "Import libs were not present in %s", lib_dir.generic_string());
2017-02-01 10:31:19 +08:00
System::println(System::color::warning,
"If this is intended, add the following line in the portfile:\n"
" SET(%s enabled)", BuildPolicies::DLLS_WITHOUT_LIBS.cmake_variable());
return lint_status::ERROR_DETECTED;
}
return lint_status::SUCCESS;
}
static lint_status check_bin_folders_are_not_present_in_static_build(const fs::path& package_dir)
{
const fs::path bin = package_dir / "bin";
const fs::path debug_bin = package_dir / "debug" / "bin";
if (!fs::exists(bin) && !fs::exists(debug_bin))
{
return lint_status::SUCCESS;
}
if (fs::exists(bin))
{
System::println(System::color::warning, R"(There should be no bin\ directory in a static build, but %s is present.)", bin.generic_string());
}
if (fs::exists(debug_bin))
{
System::println(System::color::warning, R"(There should be no debug\bin\ directory in a static build, but %s is present.)", debug_bin.generic_string());
}
System::println(System::color::warning, R"(If the creation of bin\ and/or debug\bin\ cannot be disabled, use this in the portfile to remove them)" "\n"
"\n"
R"###( if(VCPKG_LIBRARY_LINKAGE STREQUAL static))###""\n"
R"###( file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/bin ${CURRENT_PACKAGES_DIR}/debug/bin))###""\n"
R"###( endif())###"
"\n"
);
return lint_status::ERROR_DETECTED;
}
static lint_status check_no_empty_folders(const fs::path& dir)
{
2016-11-30 09:04:41 +08:00
const std::vector<fs::path> empty_directories = Files::recursive_find_matching_paths_in_dir(dir, [](const fs::path& current)
{
return fs::is_directory(current) && fs::is_empty(current);
});
if (!empty_directories.empty())
{
System::println(System::color::warning, "There should be no empty directories in %s", dir.generic_string());
System::println("The following empty directories were found: ");
2016-12-01 06:08:43 +08:00
Files::print_paths(empty_directories);
System::println(System::color::warning, "If a directory should be populated but is not, this might indicate an error in the portfile.\n"
2017-02-09 15:51:46 +08:00
"If the directories are not needed and their creation cannot be disabled, use something like this in the portfile to remove them:\n"
"\n"
R"###( file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/a/dir ${CURRENT_PACKAGES_DIR}/some/other/dir))###""\n"
"\n");
return lint_status::ERROR_DETECTED;
}
return lint_status::SUCCESS;
}
struct BuildType_and_file
{
fs::path file;
2017-02-10 11:00:09 +08:00
BuildType::type build_type;
};
2017-02-10 11:00:09 +08:00
static lint_status check_crt_linkage_of_libs(const BuildType::type& expected_build_type, const std::vector<fs::path>& libs, const fs::path dumpbin_exe)
{
2017-02-10 11:00:09 +08:00
std::vector<BuildType::type> bad_build_types(BuildType::values.cbegin(), BuildType::values.cend());
bad_build_types.erase(std::remove(bad_build_types.begin(), bad_build_types.end(), expected_build_type), bad_build_types.end());
std::vector<BuildType_and_file> libs_with_invalid_crt;
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(VCPKG_LINE_INFO, ec_data.exit_code == 0, "Running command:\n %s\n failed", Strings::utf16_to_utf8(cmd_line));
2017-02-10 11:00:09 +08:00
for (const BuildType::type& bad_build_type : bad_build_types)
{
if (std::regex_search(ec_data.output.cbegin(), ec_data.output.cend(), bad_build_type.crt_regex()))
{
2017-03-04 10:42:57 +08:00
libs_with_invalid_crt.push_back({ lib, bad_build_type });
break;
}
}
}
if (!libs_with_invalid_crt.empty())
{
System::println(System::color::warning, "Expected %s crt linkage, but the following libs had invalid crt linkage:", expected_build_type.toString());
System::println("");
for (const BuildType_and_file btf : libs_with_invalid_crt)
{
System::println(" %s: %s", btf.file.generic_string(), btf.build_type.toString());
}
System::println("");
System::println(System::color::warning, "To inspect the lib files, use:\n dumpbin.exe /directives mylibfile.lib");
return lint_status::ERROR_DETECTED;
}
return lint_status::SUCCESS;
}
2016-11-11 03:04:33 +08:00
struct OutdatedDynamicCrt_and_file
{
fs::path file;
OutdatedDynamicCrt outdated_crt;
2017-02-09 08:01:22 +08:00
OutdatedDynamicCrt_and_file() = delete;
2016-11-11 03:04:33 +08:00
};
static lint_status check_outdated_crt_linkage_of_dlls(const std::vector<fs::path>& dlls, const fs::path dumpbin_exe)
2016-11-11 03:04:33 +08:00
{
const std::vector<OutdatedDynamicCrt>& outdated_crts = get_outdated_dynamic_crts();
2016-11-11 03:04:33 +08:00
std::vector<OutdatedDynamicCrt_and_file> dlls_with_outdated_crt;
for (const fs::path& dll : dlls)
{
const std::wstring cmd_line = Strings::wformat(LR"("%s" /dependents "%s")", dumpbin_exe.native(), dll.native());
2016-11-11 03:04:33 +08:00
System::exit_code_and_output ec_data = System::cmd_execute_and_capture_output(cmd_line);
Checks::check_exit(VCPKG_LINE_INFO, ec_data.exit_code == 0, "Running command:\n %s\n failed", Strings::utf16_to_utf8(cmd_line));
2016-11-11 03:04:33 +08:00
for (const OutdatedDynamicCrt& outdated_crt : outdated_crts)
{
if (std::regex_search(ec_data.output.cbegin(), ec_data.output.cend(), outdated_crt.regex))
2016-11-11 03:04:33 +08:00
{
2017-03-04 10:42:57 +08:00
dlls_with_outdated_crt.push_back({ dll, outdated_crt });
2016-11-11 03:04:33 +08:00
break;
}
}
}
if (!dlls_with_outdated_crt.empty())
{
System::println(System::color::warning, "Detected outdated dynamic CRT in the following files:");
System::println("");
for (const OutdatedDynamicCrt_and_file btf : dlls_with_outdated_crt)
{
System::println(" %s: %s", btf.file.generic_string(), btf.outdated_crt.name);
2016-11-11 03:04:33 +08:00
}
System::println("");
System::println(System::color::warning, "To inspect the dll files, use:\n dumpbin.exe /dependents mydllfile.dll");
return lint_status::ERROR_DETECTED;
}
return lint_status::SUCCESS;
}
static lint_status check_no_files_in_package_dir_and_debug_dir(const fs::path& package_dir)
{
std::vector<fs::path> misplaced_files;
2016-11-30 09:04:41 +08:00
Files::non_recursive_find_matching_paths_in_dir(package_dir, [](const fs::path& current)
{
const std::string filename = current.filename().generic_string();
return !fs::is_directory(current) && !((_stricmp(filename.c_str(), "CONTROL") == 0 || _stricmp(filename.c_str(), "BUILD_INFO") == 0));
}, &misplaced_files);
const fs::path debug_dir = package_dir / "debug";
2016-11-30 10:08:53 +08:00
Files::non_recursive_find_all_files_in_dir(debug_dir, &misplaced_files);
if (!misplaced_files.empty())
{
System::println(System::color::warning, "The following files are placed in\n%s and\n%s: ", package_dir.generic_string(), debug_dir.generic_string());
2016-12-01 06:08:43 +08:00
Files::print_paths(misplaced_files);
System::println(System::color::warning, "Files cannot be present in those directories.\n");
return lint_status::ERROR_DETECTED;
}
return lint_status::SUCCESS;
}
2016-10-01 02:22:24 +08:00
static void operator +=(size_t& left, const lint_status& right)
2016-09-19 11:50:08 +08:00
{
2016-10-06 08:43:46 +08:00
left += static_cast<size_t>(right);
2016-09-19 11:50:08 +08:00
}
2017-04-04 05:45:00 +08:00
static size_t perform_all_checks_and_return_error_count(const PackageSpec& spec, const vcpkg_paths& paths)
2016-09-19 11:50:08 +08:00
{
// for dumpbin
const toolset_t& toolset = paths.get_toolset();
BuildInfo build_info = read_build_info(paths.build_info_file_path(spec));
const fs::path package_dir = paths.package_dir(spec);
2016-10-01 02:22:24 +08:00
size_t error_count = 0;
2017-02-08 09:02:57 +08:00
2017-03-04 11:00:48 +08:00
if (contains_and_enabled(build_info.policies, BuildPolicies::EMPTY_PACKAGE))
2017-02-08 09:02:57 +08:00
{
return error_count;
}
error_count += check_for_files_in_include_directory(build_info.policies, package_dir);
error_count += check_for_files_in_debug_include_directory(package_dir);
error_count += check_for_files_in_debug_share_directory(package_dir);
error_count += check_folder_lib_cmake(package_dir, spec);
error_count += check_for_misplaced_cmake_files(package_dir, spec);
error_count += check_folder_debug_lib_cmake(package_dir);
error_count += check_for_dlls_in_lib_dirs(package_dir);
2016-09-19 11:50:08 +08:00
error_count += check_for_copyright_file(spec, paths);
error_count += check_for_exes(package_dir);
2016-09-19 11:50:08 +08:00
2016-11-30 05:06:42 +08:00
const fs::path debug_lib_dir = package_dir / "debug" / "lib";
const fs::path release_lib_dir = package_dir / "lib";
const fs::path debug_bin_dir = package_dir / "debug" / "bin";
const fs::path release_bin_dir = package_dir / "bin";
2016-11-30 09:04:41 +08:00
const std::vector<fs::path> debug_libs = Files::recursive_find_files_with_extension_in_dir(debug_lib_dir, ".lib");
const std::vector<fs::path> release_libs = Files::recursive_find_files_with_extension_in_dir(release_lib_dir, ".lib");
error_count += check_matching_debug_and_release_binaries(debug_libs, release_libs);
std::vector<fs::path> libs;
libs.insert(libs.cend(), debug_libs.cbegin(), debug_libs.cend());
libs.insert(libs.cend(), release_libs.cbegin(), release_libs.cend());
error_count += check_lib_architecture(spec.target_triplet().architecture(), libs);
switch (build_info.library_linkage)
{
2017-02-10 11:00:09 +08:00
case LinkageType::backing_enum_t::DYNAMIC:
{
const std::vector<fs::path> debug_dlls = Files::recursive_find_files_with_extension_in_dir(debug_bin_dir, ".dll");
const std::vector<fs::path> release_dlls = Files::recursive_find_files_with_extension_in_dir(release_bin_dir, ".dll");
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<fs::path> dlls;
dlls.insert(dlls.cend(), debug_dlls.cbegin(), debug_dlls.cend());
dlls.insert(dlls.cend(), release_dlls.cbegin(), release_dlls.cend());
error_count += check_exports_of_dlls(dlls, toolset.dumpbin);
error_count += check_uwp_bit_of_dlls(spec.target_triplet().system(), dlls, toolset.dumpbin);
error_count += check_dll_architecture(spec.target_triplet().architecture(), dlls);
2016-11-11 03:04:33 +08:00
error_count += check_outdated_crt_linkage_of_dlls(dlls, toolset.dumpbin);
break;
}
2017-02-10 11:00:09 +08:00
case LinkageType::backing_enum_t::STATIC:
{
std::vector<fs::path> dlls;
Files::recursive_find_files_with_extension_in_dir(package_dir, ".dll", &dlls);
error_count += check_no_dlls_present(dlls);
error_count += check_bin_folders_are_not_present_in_static_build(package_dir);
2017-03-04 11:09:24 +08:00
if (!contains_and_enabled(build_info.policies, BuildPolicies::ONLY_RELEASE_CRT))
2017-03-04 11:00:48 +08:00
{
error_count += check_crt_linkage_of_libs(BuildType::value_of(ConfigurationType::DEBUG, build_info.crt_linkage), debug_libs, toolset.dumpbin);
2017-03-04 11:00:48 +08:00
}
error_count += check_crt_linkage_of_libs(BuildType::value_of(ConfigurationType::RELEASE, build_info.crt_linkage), release_libs, toolset.dumpbin);
break;
}
2017-02-10 11:00:09 +08:00
case LinkageType::backing_enum_t::NULLVALUE:
default:
Checks::unreachable(VCPKG_LINE_INFO);
}
2016-09-19 11:50:08 +08:00
2016-11-30 05:14:20 +08:00
error_count += check_no_empty_folders(package_dir);
error_count += check_no_files_in_package_dir_and_debug_dir(package_dir);
2017-02-08 09:02:57 +08:00
return error_count;
}
2017-04-04 05:45:00 +08:00
size_t perform_all_checks(const PackageSpec& spec, const vcpkg_paths& paths)
2017-02-08 09:02:57 +08:00
{
System::println("-- Performing post-build validation");
const size_t error_count = perform_all_checks_and_return_error_count(spec, paths);
2016-09-19 11:50:08 +08:00
if (error_count != 0)
{
const fs::path portfile = paths.ports / spec.name() / "portfile.cmake";
2016-10-01 02:22:24 +08:00
System::println(System::color::error, "Found %u error(s). Please correct the portfile:\n %s", error_count, portfile.string());
2016-09-19 11:50:08 +08:00
}
2017-03-23 04:28:10 +08:00
System::println("-- Performing post-build validation done");
return error_count;
2016-09-19 11:50:08 +08:00
}
2017-01-06 06:14:11 +08:00
}