2017-01-28 04:49:09 +08:00
# include "pch.h"
2017-04-04 07:29:11 +08:00
# include "VcpkgPaths.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"
2016-10-15 07:52:19 +08:00
# include "coff_file_reader.h"
2017-02-02 05:24:06 +08:00
# include "PostBuildLint_BuildInfo.h"
2017-02-02 05:54:08 +08:00
# include "PostBuildLint_BuildType.h"
2017-03-25 03:49:08 +08:00
# 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 ,
2016-10-12 02:32:23 +08:00
ERROR_DETECTED = 1
2016-09-19 11:50:08 +08:00
} ;
2017-02-08 14:57:37 +08:00
struct OutdatedDynamicCrt
{
std : : string name ;
std : : regex regex ;
2017-02-09 04:36:32 +08:00
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 ) ) { }
2017-02-08 14:57:37 +08:00
} ;
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) " }
2017-02-08 14:57:37 +08:00
} ;
return v ;
}
2017-03-25 03:49:08 +08:00
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 )
2017-03-25 03:49:08 +08:00
{
auto it = map . find ( key ) ;
2017-04-04 05:43:44 +08:00
if ( it ! = map . cend ( ) & & it - > second = = OptBoolT : : ENABLED )
2017-03-25 03:49:08 +08:00
{
return true ;
}
return false ;
}
2017-04-04 05:50:50 +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
{
2017-03-25 03:49:08 +08:00
if ( contains_and_enabled ( policies , BuildPolicies : : EMPTY_INCLUDE_FOLDER ) )
{
return lint_status : : SUCCESS ;
}
2016-11-30 07:32:44 +08:00
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 ) )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " The folder /include is empty. This indicates the library was not correctly installed. " ) ;
2016-10-12 02:32:23 +08:00
return lint_status : : ERROR_DETECTED ;
2016-09-19 11:50:08 +08:00
}
return lint_status : : SUCCESS ;
}
2016-11-30 07:32:44 +08:00
static lint_status check_for_files_in_debug_include_directory ( const fs : : path & package_dir )
2016-09-19 11:50:08 +08:00
{
2016-11-30 07:32:44 +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 ( ) )
{
2017-04-04 07:31:00 +08:00
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 "
2016-09-19 11:50:08 +08:00
" file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/include) "
) ;
2016-10-12 02:32:23 +08:00
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
}
2016-11-30 07:32:44 +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
{
2016-11-30 07:32:44 +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 ) )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " /debug/share should not exist. Please reorganize any important files, then use \n "
2017-03-28 07:32:51 +08:00
" file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/share) " ) ;
2016-10-12 02:32:23 +08:00
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
{
2016-11-30 07:32:44 +08:00
const fs : : path lib_cmake = package_dir / " lib " / " cmake " ;
2016-09-19 11:50:08 +08:00
if ( fs : : exists ( lib_cmake ) )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " The /lib/cmake folder should be moved to /share/%s/cmake. " , spec . name ( ) ) ;
2016-10-12 02:32:23 +08:00
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 ( ) )
{
2017-04-04 07:31:00 +08:00
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 ) ;
2016-10-12 02:32:23 +08:00
return lint_status : : ERROR_DETECTED ;
2016-09-19 11:50:08 +08:00
}
return lint_status : : SUCCESS ;
}
2016-11-30 07:32:44 +08:00
static lint_status check_folder_debug_lib_cmake ( const fs : : path & package_dir )
2016-09-19 11:50:08 +08:00
{
2016-11-30 07:32:44 +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 ) )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " The /debug/lib/cmake folder should be moved to just /debug/cmake " ) ;
2016-10-12 02:32:23 +08:00
return lint_status : : ERROR_DETECTED ;
2016-09-19 11:50:08 +08:00
}
return lint_status : : SUCCESS ;
}
2016-11-30 07:32:44 +08:00
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 ( ) )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " \n The 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 ) ;
2016-10-12 02:32:23 +08:00
return lint_status : : ERROR_DETECTED ;
2016-09-19 11:50:08 +08:00
}
return lint_status : : SUCCESS ;
}
2017-04-04 07:29:11 +08:00
static lint_status check_for_copyright_file ( const PackageSpec & spec , const VcpkgPaths & paths )
2016-09-19 11:50:08 +08:00
{
2016-11-30 07:32:44 +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 ;
}
2016-10-04 08:45:01 +08:00
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 ( ) ) ;
}
}
2017-04-04 07:31:00 +08:00
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) " ,
2016-10-04 08:45:01 +08:00
relative_path . generic_string ( ) , spec . name ( ) , spec . name ( ) , found_file . filename ( ) . generic_string ( ) , spec . name ( ) ) ;
2016-10-12 02:32:23 +08:00
return lint_status : : ERROR_DETECTED ;
2016-09-19 11:50:08 +08:00
}
if ( potential_copyright_files . size ( ) > 1 )
{
2017-04-04 07:31:00 +08:00
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
}
2016-11-30 07:32:44 +08:00
System : : println ( " %s/share/%s/copyright " , packages_dir . generic_string ( ) , spec . name ( ) ) ;
2016-10-12 02:32:23 +08:00
return lint_status : : ERROR_DETECTED ;
2016-09-19 11:50:08 +08:00
}
2016-11-30 07:32:44 +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 ( ) )
{
2017-04-04 07:31:00 +08:00
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 ) ;
2016-10-12 02:32:23 +08:00
return lint_status : : ERROR_DETECTED ;
2016-09-19 11:50:08 +08:00
}
return lint_status : : SUCCESS ;
}
2017-01-24 07:24:31 +08:00
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 )
{
2017-01-24 07:24:31 +08:00
const std : : wstring cmd_line = Strings : : wformat ( LR " ( " % s " /exports " % s " ) " , dumpbin_exe . native ( ) , dll . native ( ) ) ;
2017-04-04 07:30:11 +08:00
System : : ExitCodeAndOutput ec_data = System : : cmd_execute_and_capture_output ( cmd_line ) ;
2017-03-14 08:38:04 +08:00
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 ( ) )
{
2017-04-04 07:31:00 +08:00
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 ) ;
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " DLLs without any exports are likely a bug in the build script. " ) ;
2016-10-12 02:32:23 +08:00
return lint_status : : ERROR_DETECTED ;
2016-09-19 11:50:08 +08:00
}
return lint_status : : SUCCESS ;
}
2017-01-24 07:24:31 +08:00
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 )
{
2017-01-24 07:24:31 +08:00
const std : : wstring cmd_line = Strings : : wformat ( LR " ( " % s " /headers " % s " ) " , dumpbin_exe . native ( ) , dll . native ( ) ) ;
2017-04-04 07:30:11 +08:00
System : : ExitCodeAndOutput ec_data = System : : cmd_execute_and_capture_output ( cmd_line ) ;
2017-03-14 08:38:04 +08:00
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 ( ) )
{
2017-04-04 07:31:00 +08:00
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 ) ;
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " This bit is required for Windows Store apps. " ) ;
2016-10-12 02:32:23 +08:00
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 ;
} ;
2016-10-15 07:52:19 +08:00
static std : : string get_actual_architecture ( const MachineType & machine_type )
2016-09-19 11:50:08 +08:00
{
2016-10-15 07:52:19 +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 ) ) ;
}
}
2016-10-11 09:44:18 +08:00
2016-10-15 07:52:19 +08:00
static void print_invalid_architecture_files ( const std : : string & expected_architecture , std : : vector < file_and_arch > binaries_with_invalid_architecture )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " The following files were built for an incorrect architecture: " ) ;
2016-10-15 07:52:19 +08:00
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 ( " " ) ;
}
}
2016-10-11 09:27:47 +08:00
2016-10-15 07:52:19 +08:00
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 ;
2016-10-11 09:27:47 +08:00
2016-10-15 07:52:19 +08:00
for ( const fs : : path & file : files )
2016-09-19 11:50:08 +08:00
{
2017-03-14 08:38:04 +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 ) ;
2016-10-15 07:52:19 +08:00
const std : : string actual_architecture = get_actual_architecture ( info . machine_type ) ;
2016-10-11 09:27:47 +08:00
2016-10-15 07:52:19 +08:00
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 ( ) )
{
2016-10-15 07:52:19 +08:00
print_invalid_architecture_files ( expected_architecture , binaries_with_invalid_architecture ) ;
2016-10-12 02:32:23 +08:00
return lint_status : : ERROR_DETECTED ;
2016-10-11 09:27:47 +08:00
}
2016-10-15 07:52:19 +08:00
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 )
2016-10-11 09:27:47 +08:00
{
2017-03-14 08:38:04 +08:00
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 ) ;
2017-03-14 08:38:04 +08:00
Checks : : check_exit ( VCPKG_LINE_INFO , info . machine_types . size ( ) = = 1 , " Found more than 1 architecture in file %s " , file . generic_string ( ) ) ;
2016-10-15 07:52:19 +08:00
const std : : string actual_architecture = get_actual_architecture ( info . machine_types . at ( 0 ) ) ;
if ( expected_architecture ! = actual_architecture )
2016-10-11 09:27:47 +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
}
2016-10-15 07:52:19 +08:00
}
2016-09-19 11:50:08 +08:00
2016-10-15 07:52:19 +08:00
if ( ! binaries_with_invalid_architecture . empty ( ) )
{
print_invalid_architecture_files ( expected_architecture , binaries_with_invalid_architecture ) ;
2016-10-12 02:32:23 +08:00
return lint_status : : ERROR_DETECTED ;
2016-09-19 11:50:08 +08:00
}
return lint_status : : SUCCESS ;
}
2016-09-29 04:15:33 +08:00
static lint_status check_no_dlls_present ( const std : : vector < fs : : path > & dlls )
{
if ( dlls . empty ( ) )
{
return lint_status : : SUCCESS ;
}
2017-04-04 07:31:00 +08:00
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 ) ;
2016-10-12 02:32:23 +08:00
return lint_status : : ERROR_DETECTED ;
2016-09-29 04:15:33 +08:00
}
2016-10-23 11:00:59 +08:00
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 ;
}
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " Mismatching number of debug and release binaries. Found %d for debug but %d for release. " , debug_count , release_count ) ;
2016-10-23 11:00:59 +08:00
System : : println ( " Debug binaries " ) ;
2016-12-01 06:08:43 +08:00
Files : : print_paths ( debug_binaries ) ;
2016-10-23 11:00:59 +08:00
System : : println ( " Release binaries " ) ;
2016-12-01 06:08:43 +08:00
Files : : print_paths ( release_binaries ) ;
2016-10-23 11:00:59 +08:00
if ( debug_count = = 0 )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " Debug binaries were not found " ) ;
2016-10-23 11:00:59 +08:00
}
if ( release_count = = 0 )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " Release binaries were not found " ) ;
2016-10-23 11:00:59 +08:00
}
System : : println ( " " ) ;
return lint_status : : ERROR_DETECTED ;
}
2017-04-04 05:50:50 +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 )
2016-11-22 04:50:23 +08:00
{
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 ;
}
2016-11-22 04:50:23 +08:00
if ( lib_count = = 0 & & dll_count ! = 0 )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " Import libs were not present in %s " , lib_dir . generic_string ( ) ) ;
System : : println ( System : : Color : : warning ,
2017-02-01 10:31:19 +08:00
" If this is intended, add the following line in the portfile: \n "
2017-03-23 06:58:27 +08:00
" SET(%s enabled) " , BuildPolicies : : DLLS_WITHOUT_LIBS . cmake_variable ( ) ) ;
2016-11-22 04:50:23 +08:00
return lint_status : : ERROR_DETECTED ;
}
return lint_status : : SUCCESS ;
}
2016-11-30 07:32:44 +08:00
static lint_status check_bin_folders_are_not_present_in_static_build ( const fs : : path & package_dir )
2016-11-03 05:38:16 +08:00
{
2016-11-30 07:32:44 +08:00
const fs : : path bin = package_dir / " bin " ;
const fs : : path debug_bin = package_dir / " debug " / " bin " ;
2016-11-03 05:38:16 +08:00
if ( ! fs : : exists ( bin ) & & ! fs : : exists ( debug_bin ) )
{
return lint_status : : SUCCESS ;
}
if ( fs : : exists ( bin ) )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , R " (There should be no bin \ directory in a static build, but %s is present.) " , bin . generic_string ( ) ) ;
2016-11-03 05:38:16 +08:00
}
if ( fs : : exists ( debug_bin ) )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , R " (There should be no debug \b in \ directory in a static build, but %s is present.) " , debug_bin . generic_string ( ) ) ;
2016-11-03 05:38:16 +08:00
}
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , R " (If the creation of bin \ and/or debug \b in \ cannot be disabled, use this in the portfile to remove them) " " \n "
2016-11-03 05:38:16 +08:00
" \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 ;
}
2016-11-03 05:57:50 +08:00
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 ) ;
} ) ;
2016-11-03 05:57:50 +08:00
if ( ! empty_directories . empty ( ) )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " There should be no empty directories in %s " , dir . generic_string ( ) ) ;
2016-11-03 05:57:50 +08:00
System : : println ( " The following empty directories were found: " ) ;
2016-12-01 06:08:43 +08:00
Files : : print_paths ( empty_directories ) ;
2017-04-04 07:31:00 +08:00
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 "
2016-11-03 05:57:50 +08:00
" \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 ;
}
2016-11-10 10:44:11 +08:00
struct BuildType_and_file
2016-11-09 17:27:49 +08:00
{
2016-11-10 10:44:11 +08:00
fs : : path file ;
2017-04-04 05:51:32 +08:00
BuildType : : Type build_type ;
2016-11-09 17:27:49 +08:00
} ;
2017-04-04 05:51:32 +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 )
2016-11-09 17:27:49 +08:00
{
2017-04-04 05:51:32 +08:00
std : : vector < BuildType : : Type > bad_build_types ( BuildType : : values . cbegin ( ) , BuildType : : values . cend ( ) ) ;
2016-11-10 10:44:11 +08:00
bad_build_types . erase ( std : : remove ( bad_build_types . begin ( ) , bad_build_types . end ( ) , expected_build_type ) , bad_build_types . end ( ) ) ;
2016-11-09 17:27:49 +08:00
2016-11-10 10:44:11 +08:00
std : : vector < BuildType_and_file > libs_with_invalid_crt ;
2016-11-09 17:27:49 +08:00
for ( const fs : : path & lib : libs )
{
2017-01-24 07:24:31 +08:00
const std : : wstring cmd_line = Strings : : wformat ( LR " ( " % s " /directives " % s " ) " , dumpbin_exe . native ( ) , lib . native ( ) ) ;
2017-04-04 07:30:11 +08:00
System : : ExitCodeAndOutput ec_data = System : : cmd_execute_and_capture_output ( cmd_line ) ;
2017-03-14 08:38:04 +08:00
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-09 17:27:49 +08:00
2017-04-04 05:51:32 +08:00
for ( const BuildType : : Type & bad_build_type : bad_build_types )
2016-11-09 17:27:49 +08:00
{
2016-11-10 10:44:11 +08:00
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 } ) ;
2016-11-10 10:44:11 +08:00
break ;
}
2016-11-09 17:27:49 +08:00
}
}
2016-11-10 10:44:11 +08:00
if ( ! libs_with_invalid_crt . empty ( ) )
2016-11-09 17:27:49 +08:00
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " Expected %s crt linkage, but the following libs had invalid crt linkage: " , expected_build_type . toString ( ) ) ;
2016-11-10 10:44:11 +08:00
System : : println ( " " ) ;
for ( const BuildType_and_file btf : libs_with_invalid_crt )
2016-11-09 17:27:49 +08:00
{
2016-11-10 10:44:11 +08:00
System : : println ( " %s: %s " , btf . file . generic_string ( ) , btf . build_type . toString ( ) ) ;
2016-11-09 17:27:49 +08:00
}
2016-11-10 10:44:11 +08:00
System : : println ( " " ) ;
2016-11-09 17:27:49 +08:00
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " To inspect the lib files, use: \n dumpbin.exe /directives mylibfile.lib " ) ;
2016-11-10 10:44:11 +08:00
return lint_status : : ERROR_DETECTED ;
2016-11-09 17:27:49 +08:00
}
2016-11-10 10:44:11 +08:00
return lint_status : : SUCCESS ;
2016-11-09 17:27:49 +08:00
}
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
} ;
2017-01-24 07:24:31 +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
{
2017-02-08 14:57:37 +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 )
{
2017-01-24 07:24:31 +08:00
const std : : wstring cmd_line = Strings : : wformat ( LR " ( " % s " /dependents " % s " ) " , dumpbin_exe . native ( ) , dll . native ( ) ) ;
2017-04-04 07:30:11 +08:00
System : : ExitCodeAndOutput ec_data = System : : cmd_execute_and_capture_output ( cmd_line ) ;
2017-03-14 08:38:04 +08:00
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 )
{
2017-02-08 14:57:37 +08:00
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 ( ) )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " Detected outdated dynamic CRT in the following files: " ) ;
2016-11-11 03:04:33 +08:00
System : : println ( " " ) ;
for ( const OutdatedDynamicCrt_and_file btf : dlls_with_outdated_crt )
{
2017-02-08 14:57:37 +08:00
System : : println ( " %s: %s " , btf . file . generic_string ( ) , btf . outdated_crt . name ) ;
2016-11-11 03:04:33 +08:00
}
System : : println ( " " ) ;
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " To inspect the dll files, use: \n dumpbin.exe /dependents mydllfile.dll " ) ;
2016-11-11 03:04:33 +08:00
return lint_status : : ERROR_DETECTED ;
}
return lint_status : : SUCCESS ;
}
2016-11-30 05:07:21 +08:00
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 ) ;
2016-11-30 05:07:21 +08:00
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 ) ;
2016-11-30 05:07:21 +08:00
if ( ! misplaced_files . empty ( ) )
{
2017-04-04 07:31:00 +08:00
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 ) ;
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " Files cannot be present in those directories. \n " ) ;
2016-11-30 05:07:21 +08:00
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 07:29:11 +08:00
static size_t perform_all_checks_and_return_error_count ( const PackageSpec & spec , const VcpkgPaths & paths )
2016-09-19 11:50:08 +08:00
{
2017-04-01 17:08:48 +08:00
// for dumpbin
2017-04-04 07:28:18 +08:00
const Toolset & toolset = paths . get_toolset ( ) ;
2017-01-24 07:24:31 +08:00
2016-11-09 06:12:49 +08:00
BuildInfo build_info = read_build_info ( paths . build_info_file_path ( spec ) ) ;
2016-11-30 07:32:44 +08:00
const fs : : path package_dir = paths . package_dir ( spec ) ;
2016-11-09 06:12:49 +08:00
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 ;
}
2017-03-25 03:49:08 +08:00
error_count + = check_for_files_in_include_directory ( build_info . policies , package_dir ) ;
2016-11-30 07:32:44 +08:00
error_count + = check_for_files_in_debug_include_directory ( package_dir ) ;
error_count + = check_for_files_in_debug_share_directory ( package_dir ) ;
2017-03-16 07:14:02 +08:00
error_count + = check_folder_lib_cmake ( package_dir , spec ) ;
2016-11-30 07:32:44 +08:00
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 ) ;
2016-11-30 07:32:44 +08:00
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-22 04:50:23 +08:00
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 " ) ;
2016-11-09 11:33:50 +08:00
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 ) ;
2017-02-10 10:39:03 +08:00
switch ( build_info . library_linkage )
2016-09-29 04:15:33 +08:00
{
2017-04-04 05:52:47 +08:00
case LinkageType : : BackingEnum : : DYNAMIC :
2017-02-08 14:57:37 +08:00
{
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 " ) ;
2016-10-23 11:00:59 +08:00
2017-02-08 14:57:37 +08:00
error_count + = check_matching_debug_and_release_binaries ( debug_dlls , release_dlls ) ;
2016-10-23 11:00:59 +08:00
2017-02-08 14:57:37 +08:00
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 ) ;
2016-11-22 04:50:23 +08:00
2017-02-08 14:57:37 +08:00
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 ( ) ) ;
2016-09-29 04:15:33 +08:00
2017-04-01 17:08:48 +08:00
error_count + = check_exports_of_dlls ( dlls , toolset . dumpbin ) ;
error_count + = check_uwp_bit_of_dlls ( spec . target_triplet ( ) . system ( ) , dlls , toolset . dumpbin ) ;
2017-02-08 14:57:37 +08:00
error_count + = check_dll_architecture ( spec . target_triplet ( ) . architecture ( ) , dlls ) ;
2016-11-11 03:04:33 +08:00
2017-04-01 17:08:48 +08:00
error_count + = check_outdated_crt_linkage_of_dlls ( dlls , toolset . dumpbin ) ;
2017-02-08 14:57:37 +08:00
break ;
}
2017-04-04 05:52:47 +08:00
case LinkageType : : BackingEnum : : STATIC :
2017-02-08 14:57:37 +08:00
{
std : : vector < fs : : path > dlls ;
Files : : recursive_find_files_with_extension_in_dir ( package_dir , " .dll " , & dlls ) ;
error_count + = check_no_dlls_present ( dlls ) ;
2016-10-15 07:52:19 +08:00
2017-02-08 14:57:37 +08:00
error_count + = check_bin_folders_are_not_present_in_static_build ( package_dir ) ;
2016-11-09 17:27:49 +08:00
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
{
2017-04-01 17:08: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
}
2017-04-01 17:08:48 +08:00
error_count + = check_crt_linkage_of_libs ( BuildType : : value_of ( ConfigurationType : : RELEASE , build_info . crt_linkage ) , release_libs , toolset . dumpbin ) ;
2017-02-08 14:57:37 +08:00
break ;
}
2017-04-04 05:52:47 +08:00
case LinkageType : : BackingEnum : : NULLVALUE :
2017-02-08 14:57:37 +08:00
default :
2017-03-14 07:59:21 +08:00
Checks : : unreachable ( VCPKG_LINE_INFO ) ;
2016-09-29 04:15:33 +08:00
}
2016-09-19 11:50:08 +08:00
2016-11-30 05:14:20 +08:00
error_count + = check_no_empty_folders ( package_dir ) ;
2016-11-30 05:07:21 +08:00
error_count + = check_no_files_in_package_dir_and_debug_dir ( package_dir ) ;
2016-11-03 05:57:50 +08:00
2017-02-08 09:02:57 +08:00
return error_count ;
}
2017-04-04 07:29:11 +08:00
size_t perform_all_checks ( const PackageSpec & spec , const VcpkgPaths & 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 )
{
2016-10-04 08:45:01 +08:00
const fs : : path portfile = paths . ports / spec . name ( ) / " portfile.cmake " ;
2017-04-04 07:31:00 +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 " ) ;
2017-02-04 10:10:29 +08:00
return error_count ;
2016-09-19 11:50:08 +08:00
}
2017-01-06 06:14:11 +08:00
}