@ -8,7 +8,10 @@
# include <cstdio>
# include <cstring>
# include <fstream>
# include <iomanip>
# include <new>
# include <nlohmann/json.hpp>
# include <regex>
# include <sstream>
# include <stdexcept>
# include <string>
@ -160,7 +163,7 @@ struct Command {
~ Command ( ) {
if ( ! generated ) {
assert ( false & & " Incorrect usage of cmd() " ) ;
assert ( false & & " Incorrect usage of cmd() , you probably forgot () " ) ;
}
}
@ -403,6 +406,31 @@ struct Generator {
}
} ;
static std : : string vcpkg_escape_identifier ( const std : : string & name ) {
// Do a reasonable effort to escape the project name for use with vcpkg
std : : string escaped ;
for ( char ch : name ) {
if ( ( ch & 0x80 ) ! = 0 ) {
throw std : : runtime_error ( " Non-ASCII characters are not allowed in [project].name when using [vcpkg] " ) ;
}
if ( ch = = ' _ ' | | ch = = ' ' ) {
ch = ' - ' ;
}
escaped + = std : : tolower ( ch ) ;
}
const std : : regex reserved ( " prn|aux|nul|con|lpt[1-9]|com[1-9]|core|default " ) ;
const std : : regex ok ( " [a-z0-9]+(-[a-z0-9]+)* " ) ;
std : : cmatch m ;
if ( ! std : : regex_match ( escaped . c_str ( ) , m , reserved ) & & std : : regex_match ( escaped . c_str ( ) , m , ok ) ) {
return escaped ;
} else {
throw std : : runtime_error ( " The escaped project name ' " + escaped + " ' is not usable with [vcpkg] " ) ;
}
}
int generate_cmake ( const char * path , bool root ) {
if ( ! fs : : exists ( fs : : path ( path ) / " cmake.toml " ) ) {
throw std : : runtime_error ( " No cmake.toml found! " ) ;
@ -419,8 +447,9 @@ int generate_cmake(const char *path, bool root) {
auto inject_includes = [ & gen ] ( const std : : vector < std : : string > & includes ) { gen . inject_includes ( includes ) ; } ;
auto inject_cmake = [ & gen ] ( const std : : string & cmake ) { gen . inject_cmake ( cmake ) ; } ;
std : : string cmkr_url = " https://github.com/build-cpp/cmkr " ;
comment ( " This file is automatically generated from cmake.toml - DO NOT EDIT " ) ;
comment ( " See https://github.com/build-cpp/cmkr for more information" ) ;
comment ( " See " + cmkr_url + " for more information" ) ;
endl ( ) ;
if ( root ) {
@ -520,15 +549,45 @@ int generate_cmake(const char *path, bool root) {
}
}
if ( ! cmake . vcpkg . version . empty ( ) ) {
assert ( " pmm is required in fetch-content for vcpkg to work " & & cmake . contents . count ( " pmm " ) ! = 0 ) ;
comment ( " Bootstrap vcpkg " ) ;
cmd ( " include " ) ( " ${pmm_SOURCE_DIR}/pmm.cmake " ) ;
tsl : : ordered_map < std : : string , std : : vector < std : : string > > vcpkg_args ;
vcpkg_args [ " REVISION " ] = { cmake . vcpkg . version } ;
vcpkg_args [ " REQUIRES " ] = cmake . vcpkg . packages ;
auto vcpkg = std : : make_pair ( " VCPKG " , vcpkg_args ) ;
cmd ( " pmm " ) ( vcpkg ) . endl ( ) ;
if ( ! cmake . vcpkg . packages . empty ( ) ) {
// Allow the user to specify a url or derive it from the version
auto url = cmake . vcpkg . url ;
if ( url . empty ( ) ) {
if ( cmake . vcpkg . version . empty ( ) ) {
throw std : : runtime_error ( " You need either [vcpkg].version or [vcpkg].url " ) ;
}
url = " https://github.com/microsoft/vcpkg/archive/refs/tags/ " + cmake . vcpkg . version + " .tar.gz " ;
}
// CMake to bootstrap vcpkg and download the packages
// clang-format off
cmd ( " if " ) ( " CMKR_ROOT_PROJECT " , " AND " , " NOT " , " CMKR_DISABLE_VCPKG " ) ;
cmd ( " include " ) ( " FetchContent " ) ;
cmd ( " message " ) ( " STATUS " , " Fetching vcpkg... " ) ;
cmd ( " FetchContent_Declare " ) ( " vcpkg " , " URL " , url ) ;
cmd ( " FetchContent_MakeAvailable " ) ( " vcpkg " ) ;
cmd ( " include " ) ( " ${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake " ) ;
cmd ( " endif " ) ( ) ;
// clang-format on
// Generate vcpkg.json
using namespace nlohmann ;
json j ;
j [ " $cmkr " ] = " This file is automatically generated from cmake.toml - DO NOT EDIT " ;
j [ " $cmkr-url " ] = cmkr_url ;
j [ " $schema " ] = " https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json " ;
j [ " name " ] = vcpkg_escape_identifier ( cmake . project_name ) ;
j [ " version-string " ] = cmake . project_version ;
j [ " dependencies " ] = cmake . vcpkg . packages ;
if ( ! cmake . project_description . empty ( ) ) {
j [ " description " ] = cmake . project_description ;
}
std : : ofstream ofs ( " vcpkg.json " ) ;
if ( ! ofs ) {
throw std : : runtime_error ( " Failed to create a vcpkg.json manifest file! " ) ;
}
ofs < < std : : setw ( 2 ) < < j < < std : : endl ;
}
if ( ! cmake . packages . empty ( ) ) {
@ -683,7 +742,7 @@ int generate_cmake(const char *path, bool root) {
}
if ( ! target . sources . empty ( ) ) {
cmd ( " source_group " ) ( " TREE " , " ${CMAKE_CURRENT_SOURCE_DIR} " , " FILES " , " ${ " + target. name + " _SOURCES }" ) . endl ( ) ;
cmd ( " source_group " ) ( " TREE " , " ${CMAKE_CURRENT_SOURCE_DIR} " , " FILES " , " ${ " + sources_var + " }" ) . endl ( ) ;
}
if ( ! target . alias . empty ( ) ) {