2017-01-28 04:49:09 +08:00
# include "pch.h"
2017-01-13 09:03:21 +08:00
# include "vcpkg_Commands.h"
# include "StatusParagraphs.h"
2017-01-26 11:32:50 +08:00
# include "vcpkglib.h"
2017-01-13 09:03:21 +08:00
# include "vcpkg_Input.h"
2017-02-02 05:24:06 +08:00
# include "PostBuildLint.h"
2017-01-13 09:03:21 +08:00
# include "vcpkg_Dependencies.h"
# include "vcpkg_System.h"
2017-03-04 22:25:05 +08:00
# include "vcpkg_Chrono.h"
2017-01-13 09:03:21 +08:00
# include "metrics.h"
2017-02-16 06:34:03 +08:00
# include "vcpkg_Enums.h"
2017-02-28 07:52:57 +08:00
# include "Paragraphs.h"
2017-01-13 09:03:21 +08:00
2017-01-13 14:03:57 +08:00
namespace vcpkg : : Commands : : Build
2017-01-13 09:03:21 +08:00
{
2017-04-04 07:23:23 +08:00
using Dependencies : : PackageSpecWithInstallPlan ;
2017-04-04 07:22:32 +08:00
using Dependencies : : InstallPlanType ;
2017-01-13 09:03:21 +08:00
static const std : : string OPTION_CHECKS_ONLY = " --checks-only " ;
2017-04-04 07:29:11 +08:00
static void create_binary_control_file ( const VcpkgPaths & paths , const SourceParagraph & source_paragraph , const Triplet & target_triplet )
2017-01-13 09:03:21 +08:00
{
const BinaryParagraph bpgh = BinaryParagraph ( source_paragraph , target_triplet ) ;
const fs : : path binary_control_file = paths . packages / bpgh . dir ( ) / " CONTROL " ;
std : : ofstream ( binary_control_file ) < < bpgh ;
}
2017-04-04 07:28:18 +08:00
std : : wstring make_build_env_cmd ( const Triplet & target_triplet , const Toolset & toolset )
2017-04-04 01:44:14 +08:00
{
2017-04-07 07:51:13 +08:00
const wchar_t * tonull = L " >nul " ;
if ( g_debugging )
{
tonull = L " " ;
}
return Strings : : wformat ( LR " ( " % s " %s %s 2>&1) " , toolset . vcvarsall . native ( ) , Strings : : utf8_to_utf16 ( target_triplet . architecture ( ) ) , tonull ) ;
2017-04-04 01:44:14 +08:00
}
2017-04-04 07:29:11 +08:00
BuildResult build_package ( const SourceParagraph & source_paragraph , const PackageSpec & spec , const VcpkgPaths & paths , const fs : : path & port_dir , const StatusParagraphs & status_db )
2017-01-13 09:03:21 +08:00
{
2017-03-14 08:38:04 +08:00
Checks : : check_exit ( VCPKG_LINE_INFO , spec . name ( ) = = source_paragraph . name , " inconsistent arguments to build_package() " ) ;
2017-01-13 09:35:33 +08:00
2017-04-04 06:02:45 +08:00
const Triplet & target_triplet = spec . target_triplet ( ) ;
2017-03-16 10:46:55 +08:00
for ( auto & & dep : filter_dependencies ( source_paragraph . depends , target_triplet ) )
2017-02-14 06:01:27 +08:00
{
2017-03-16 10:46:55 +08:00
if ( status_db . find_installed ( dep , target_triplet ) = = status_db . end ( ) )
2017-02-14 06:01:27 +08:00
{
return BuildResult : : CASCADED_DUE_TO_MISSING_DEPENDENCIES ;
}
}
2017-01-13 09:35:33 +08:00
2017-03-11 08:40:43 +08:00
const fs : : path & cmake_exe_path = paths . get_cmake_exe ( ) ;
const fs : : path & git_exe_path = paths . get_git_exe ( ) ;
2017-02-23 20:35:00 +08:00
2017-01-13 09:35:33 +08:00
const fs : : path ports_cmake_script_path = paths . ports_cmake ;
2017-04-04 07:28:18 +08:00
const Toolset & toolset = paths . get_toolset ( ) ;
2017-04-04 01:44:14 +08:00
const auto cmd_set_environment = make_build_env_cmd ( target_triplet , toolset ) ;
2017-01-13 09:35:33 +08:00
2017-03-11 08:40:43 +08:00
const std : : wstring cmd_launch_cmake = make_cmake_cmd ( cmake_exe_path , ports_cmake_script_path ,
{
{ L " CMD " , L " BUILD " } ,
{ L " PORT " , source_paragraph . name } ,
{ L " CURRENT_PORT_DIR " , port_dir / " /. " } ,
{ L " TARGET_TRIPLET " , target_triplet . canonical_name ( ) } ,
2017-04-01 17:08:48 +08:00
{ L " VCPKG_PLATFORM_TOOLSET " , toolset . version } ,
2017-03-11 08:40:43 +08:00
{ L " GIT " , git_exe_path }
} ) ;
const std : : wstring command = Strings : : wformat ( LR " (%s && %s) " , cmd_set_environment , cmd_launch_cmake ) ;
2017-04-04 06:44:46 +08:00
const ElapsedTime timer = ElapsedTime : : create_started ( ) ;
2017-03-04 22:25:05 +08:00
2017-03-11 09:03:47 +08:00
int return_code = System : : cmd_execute_clean ( command ) ;
2017-03-04 22:25:05 +08:00
auto buildtimeus = timer . microseconds ( ) ;
2017-04-04 08:06:53 +08:00
Metrics : : track_metric ( " buildtimeus- " + spec . to_string ( ) , buildtimeus ) ;
2017-01-13 09:35:33 +08:00
if ( return_code ! = 0 )
2017-01-13 09:03:21 +08:00
{
2017-04-04 05:41:36 +08:00
Metrics : : track_property ( " error " , " build failed " ) ;
2017-04-04 08:06:53 +08:00
Metrics : : track_property ( " build_error " , spec . to_string ( ) ) ;
2017-02-04 10:10:29 +08:00
return BuildResult : : BUILD_FAILED ;
2017-01-13 09:35:33 +08:00
}
2017-01-13 09:03:21 +08:00
2017-02-04 10:10:29 +08:00
const size_t error_count = PostBuildLint : : perform_all_checks ( spec , paths ) ;
if ( error_count ! = 0 )
{
return BuildResult : : POST_BUILD_CHECKS_FAILED ;
}
2017-01-13 09:03:21 +08:00
2017-01-13 09:35:33 +08:00
create_binary_control_file ( paths , source_paragraph , target_triplet ) ;
2017-01-13 09:03:21 +08:00
2017-01-13 09:35:33 +08:00
// const fs::path port_buildtrees_dir = paths.buildtrees / spec.name;
// delete_directory(port_buildtrees_dir);
2017-02-04 10:10:29 +08:00
2017-02-14 06:01:27 +08:00
return BuildResult : : SUCCEEDED ;
2017-01-13 09:03:21 +08:00
}
2017-01-13 09:35:33 +08:00
2017-02-14 06:01:27 +08:00
const std : : string & to_string ( const BuildResult build_result )
2017-01-13 09:03:21 +08:00
{
2017-04-04 07:25:12 +08:00
static const std : : string NULLVALUE_STRING = Enums : : nullvalue_to_string ( " vcpkg::Commands::Build::BuildResult " ) ;
2017-02-14 06:01:27 +08:00
static const std : : string SUCCEEDED_STRING = " SUCCEEDED " ;
static const std : : string BUILD_FAILED_STRING = " BUILD_FAILED " ;
static const std : : string POST_BUILD_CHECKS_FAILED_STRING = " POST_BUILD_CHECKS_FAILED " ;
static const std : : string CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING = " CASCADED_DUE_TO_MISSING_DEPENDENCIES " ;
2017-01-13 09:03:21 +08:00
2017-02-14 06:01:27 +08:00
switch ( build_result )
2017-02-11 09:00:46 +08:00
{
2017-02-16 06:34:03 +08:00
case BuildResult : : NULLVALUE : return NULLVALUE_STRING ;
2017-02-14 06:01:27 +08:00
case BuildResult : : SUCCEEDED : return SUCCEEDED_STRING ;
case BuildResult : : BUILD_FAILED : return BUILD_FAILED_STRING ;
case BuildResult : : POST_BUILD_CHECKS_FAILED : return POST_BUILD_CHECKS_FAILED_STRING ;
case BuildResult : : CASCADED_DUE_TO_MISSING_DEPENDENCIES : return CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING ;
2017-03-14 07:59:21 +08:00
default : Checks : : unreachable ( VCPKG_LINE_INFO ) ;
2017-02-11 09:00:46 +08:00
}
2017-02-14 06:01:27 +08:00
}
2017-01-13 09:03:21 +08:00
2017-04-04 05:45:00 +08:00
std : : string create_error_message ( const BuildResult build_result , const PackageSpec & spec )
2017-02-14 06:01:27 +08:00
{
2017-04-04 08:06:53 +08:00
return Strings : : format ( " Error: Building package %s failed with: %s " , spec . to_string ( ) , Build : : to_string ( build_result ) ) ;
2017-02-11 09:00:46 +08:00
}
2017-01-13 09:03:21 +08:00
2017-04-04 05:45:00 +08:00
std : : string create_user_troubleshooting_message ( const PackageSpec & spec )
2017-02-14 08:22:02 +08:00
{
2017-03-18 05:55:46 +08:00
return Strings : : format ( " Please ensure you're using the latest portfiles with `. \\ vcpkg update`, then \n "
2017-02-14 08:22:02 +08:00
" submit an issue at https://github.com/Microsoft/vcpkg/issues including: \n "
" Package: %s \n "
" Vcpkg version: %s \n "
" \n "
" Additionally, attach any relevant sections from the log files above. "
2017-04-04 08:06:53 +08:00
, spec . to_string ( ) , Version : : version ( ) ) ;
2017-02-14 08:22:02 +08:00
}
2017-01-13 09:03:21 +08:00
2017-04-04 07:29:11 +08:00
void perform_and_exit ( const PackageSpec & spec , const fs : : path & port_dir , const std : : unordered_set < std : : string > & options , const VcpkgPaths & paths )
2017-01-13 09:03:21 +08:00
{
if ( options . find ( OPTION_CHECKS_ONLY ) ! = options . end ( ) )
{
2017-02-04 10:10:29 +08:00
const size_t error_count = PostBuildLint : : perform_all_checks ( spec , paths ) ;
2017-03-23 08:45:39 +08:00
Checks : : check_exit ( VCPKG_LINE_INFO , error_count = = 0 ) ;
Checks : : exit_success ( VCPKG_LINE_INFO ) ;
2017-01-13 09:03:21 +08:00
}
2017-04-04 07:26:54 +08:00
const Expected < SourceParagraph > maybe_spgh = Paragraphs : : try_load_port ( port_dir ) ;
2017-04-08 07:01:09 +08:00
Checks : : check_exit ( VCPKG_LINE_INFO , ! maybe_spgh . error_code ( ) , " Could not find package named %s: %s " , spec . display_name ( ) , maybe_spgh . error_code ( ) . message ( ) ) ;
2017-01-13 09:03:21 +08:00
const SourceParagraph & spgh = * maybe_spgh . get ( ) ;
2017-02-17 16:05:45 +08:00
StatusParagraphs status_db = database_load_check ( paths ) ;
2017-02-14 06:01:27 +08:00
const BuildResult result = build_package ( spgh , spec , paths , paths . port_dir ( spec ) , status_db ) ;
if ( result = = BuildResult : : CASCADED_DUE_TO_MISSING_DEPENDENCIES )
2017-01-13 09:03:21 +08:00
{
2017-04-04 07:23:23 +08:00
std : : vector < PackageSpecWithInstallPlan > unmet_dependencies = Dependencies : : create_install_plan ( paths , { spec } , status_db ) ;
2017-02-11 09:00:46 +08:00
unmet_dependencies . erase (
2017-04-04 07:23:23 +08:00
std : : remove_if ( unmet_dependencies . begin ( ) , unmet_dependencies . end ( ) , [ & spec ] ( const PackageSpecWithInstallPlan & p )
2017-02-11 09:00:46 +08:00
{
2017-04-04 07:22:32 +08:00
return ( p . spec = = spec ) | | ( p . plan . plan_type = = InstallPlanType : : ALREADY_INSTALLED ) ;
2017-02-11 09:00:46 +08:00
} ) ,
unmet_dependencies . end ( ) ) ;
2017-03-14 08:38:04 +08:00
Checks : : check_exit ( VCPKG_LINE_INFO , ! unmet_dependencies . empty ( ) ) ;
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : error , " The build command requires all dependencies to be already installed. " ) ;
2017-01-13 09:03:21 +08:00
System : : println ( " The following dependencies are missing: " ) ;
System : : println ( " " ) ;
2017-04-04 07:23:23 +08:00
for ( const PackageSpecWithInstallPlan & p : unmet_dependencies )
2017-01-13 09:03:21 +08:00
{
2017-04-04 08:06:53 +08:00
System : : println ( " %s " , p . spec . to_string ( ) ) ;
2017-01-13 09:03:21 +08:00
}
System : : println ( " " ) ;
2017-03-23 08:45:39 +08:00
Checks : : exit_fail ( VCPKG_LINE_INFO ) ;
2017-01-13 09:03:21 +08:00
}
2017-02-14 06:01:27 +08:00
if ( result ! = BuildResult : : SUCCEEDED )
2017-02-04 10:10:29 +08:00
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : error , Build : : create_error_message ( result , spec ) ) ;
2017-02-14 08:22:02 +08:00
System : : println ( Build : : create_user_troubleshooting_message ( spec ) ) ;
2017-03-23 08:45:39 +08:00
Checks : : exit_fail ( VCPKG_LINE_INFO ) ;
2017-02-04 10:10:29 +08:00
}
2017-03-23 08:45:39 +08:00
Checks : : exit_success ( VCPKG_LINE_INFO ) ;
2017-01-13 09:03:21 +08:00
}
2017-02-18 06:55:37 +08:00
2017-04-04 07:29:11 +08:00
void perform_and_exit ( const VcpkgCmdArguments & args , const VcpkgPaths & paths , const Triplet & default_target_triplet )
2017-02-18 06:55:37 +08:00
{
static const std : : string example = Commands : : Help : : create_example_string ( " build zlib:x64-windows " ) ;
args . check_exact_arg_count ( 1 , example ) ; // Build only takes a single package and all dependencies must already be installed
2017-04-04 05:45:00 +08:00
const PackageSpec spec = Input : : check_and_get_package_spec ( args . command_arguments . at ( 0 ) , default_target_triplet , example ) ;
2017-02-18 06:55:37 +08:00
Input : : check_triplet ( spec . target_triplet ( ) , paths ) ;
const std : : unordered_set < std : : string > options = args . check_and_get_optional_command_arguments ( { OPTION_CHECKS_ONLY } ) ;
perform_and_exit ( spec , paths . port_dir ( spec ) , options , paths ) ;
}
2017-01-13 09:03:21 +08:00
}