diff --git a/doc/src/tasks.adoc b/doc/src/tasks.adoc index 53152af569..995fcf53da 100644 --- a/doc/src/tasks.adoc +++ b/doc/src/tasks.adoc @@ -726,3 +726,7 @@ managers. Currently the supported ones are: * Conan (`conan`): currently supports the link:https://docs.conan.io/en/latest/reference/generators/b2.html[`b2 generator`]. + +:leveloffset: +1 +include::../../src/tools/vcpkg.jam[tag=doc] +:leveloffset: -1 diff --git a/src/build/ac.jam b/src/build/ac.jam index 02ae62bdb6..f22550a2be 100644 --- a/src/build/ac.jam +++ b/src/build/ac.jam @@ -199,9 +199,17 @@ class ac-library : basic-target else { local use-environment ; + local vcpkg-ps ; if ! $(self.library-name) && ! $(self.include-path) && ! $(self.library-path) { use-environment = true ; + local vcpkg-proj = [ project.target vcpkg : allow-missing ] ; + if $(vcpkg-proj) + { + vcpkg-ps = [ targets.generate-from-reference + /vcpkg//prefix : $(vcpkg-proj) : $(property-set) ] ; + } + } local libnames = $(self.library-name) ; if ! $(libnames) && $(use-environment) @@ -213,12 +221,20 @@ class ac-library : basic-target libnames ?= $(self.default-names) ; local include-path = $(self.include-path) ; + if ! $(include-path) && $(vcpkg-ps) + { + include-path = [ $(vcpkg-ps).get ] ; + } if ! $(include-path) && $(use-environment) { include-path = [ os.environ $(name:U)_INCLUDE ] ; } local library-path = $(self.library-path) ; + if ! $(library-path) && $(vcpkg-ps) + { + library-path = [ $(vcpkg-ps).get ] ; + } if ! $(library-path) && $(use-environment) { library-path = [ os.environ $(name:U)_LIBRARY_PATH ] ; diff --git a/src/tools/vcpkg.jam b/src/tools/vcpkg.jam new file mode 100644 index 0000000000..16538604a5 --- /dev/null +++ b/src/tools/vcpkg.jam @@ -0,0 +1,393 @@ +#| +Copyright 2023 Dmitry Arkhipov (grisumbras@yandex.ru) +Distributed under the Boost Software License, Version 1.0. (See +accompanying file LICENSE.txt or copy at +https://www.bfgroup.xyz/b2/LICENSE.txt) +|# + +import errors ; +import feature ; +import msvc ; +import os ; +import path ; +import project ; +import property ; +import targets ; + +#| tag::doc[] + += vcpkg support +https://learn.microsoft.com/vcpkg[vcpkg] is a cross-platform package manager +for C and {CPP} developed by Microsoft. vcpkg provides first-class support +for CMake and MSBuild build systems, but you can still use packages installed +by vcpkg in b2 either as link:#bbv2.tutorial.prebuilt[prebuilt libraries], +with the help of link:#_pkg_config[pkg-config] tool, or if the package provides +a link:#bbv2.extending.toolset_modules[toolset module]. + +The module declares the project `/vcpkg` with a main target `/vcpkg//prefix`. +The target can be used as a dependency to add its `` and `` +usage requirements. + +[source, jam] +---- +lib sqlite3 : /vcpkg//prefix ; +---- + +|# # end::doc[] + +if --debug-configuration in [ modules.peek : ARGV ] +{ + .debug = true ; +} + +#| tag::doc[] + + +== Initialization +To enable vcpkg integration you need to declare it in a configuration file +with the help of `using` rule: + +[source, jam] +---- +using vcpkg : [options] ... : [ requirements ] ... ; +---- + +* `options`: options that specify the location of vcpkg package installation + tree. Allowed options are: + + ** ``: directory with header files; + ** ``: directory with library binaries; + ** ``: installation prefix for the triplet; + ** ``: the triplet to use; + ** ``: vcpkg installation root. + +* `requirements`: properties that distinguish this configuration. + +If options do contain neither `` nor ``, they are set +to `include` and `lib` subdirectories of ``. + +If options do not contain ``, it is set to `/`. + +If options do not contain ``, it is set to `installed` subdirectory of +the directory pointed to by `VCPKG_ROOT` environment variable if it is not +empty. Otherwise, +https://learn.microsoft.com/vcpkg/users/manifests[Manisfest mode] is assumed, +and `vcpkg.json` file is searched for in the current directory and its parents. +If the file is found, then `` is set to `vcpkg_installed` subdirectory +of its parent directory. + +If options do not contain ``, it is set to the value of +`VCPKG_DEFAULT_TRIPLET` environment variable if it is not empty. Otherwise, +if there is exactly one triplet subdirectory of `` directory, then its +name is used. + +If requirements do not contain a property of ``, and options do not +contain ``, then two versions are configured: one for +`release` that sets `` to `/lib`, and another for +`debug` that sets `` to `/debug/lib`. + +Finally, if options contain none of ``, ``, ``, and +`` and requirements are empty, appropriate configurations for several +default triplets provided by vcpkg are made. + +|# # end::doc[] + +rule init ( options * : requirements * ) +{ + local incdir = [ feature.get-values : $(options) ] ; + local libdir = [ feature.get-values : $(options) ] ; + local prefix = [ feature.get-values : $(options) ] ; + local root = [ feature.get-values : $(options) ] ; + local triplet = [ feature.get-values : $(options) ] ; + + if ( ( $(root) || $(triplet) ) && ( $(prefix) || $(incdir) || $(libdir) ) ) + || ( $(prefix) && ( $(incdir) || $(libdir) ) ) + || ( $(incdir) && ! $(libdir) ) + || ( $(libdir) && ! $(incdir) ) + { + errors.user-error "incompatible options for vcpkg:" $(options) ; + } + + local kind = predefined-triplets ; + if $(prefix) || $(incdir) || $(libdir) + { + kind = specific-triplet ; + } + else + { + if $(triplet) || $(requirements) + { + kind = specific-triplet ; + } + } + + if ! $(.initialized) + { + .initialized = true ; + + project.initialize $(__name__) ; + project $(__name__) ; + } + else + { + if ! $(options) && ! $(requirements) + { + kind = ; + } + } + + local project = [ project.target $(__name__) ] ; + + switch $(kind) + { + case predefined-triplets : + configure-predefined $(project) : $(root) ; + case specific-triplet : + configure-specific $(project) : $(root) : $(triplet) : $(prefix) + : $(incdir) : $(libdir) : $(requirements) ; + } +} + + +local rule configure-predefined ( project : root ? ) +{ + if ! $(root) + { + root = [ deduce-root ] ; + } + + # arm-neon-android, arm6-android, arm64ec-windows, wasm32-emscripten, + # all xbox, mingw, and -release triplets are skipped + + # Linux + configure-specific $(project) : $(root) : x64-linux : : : + : linux static shared ; + configure-specific $(project) : $(root) : x64-linux-dynamic : : : + : linux shared shared ; + + configure-specific $(project) : $(root) : x86-linux : : : + : linux 32 static shared ; + + configure-specific $(project) : $(root) : arm-linux : : : + : linux 32 arm static shared ; + + configure-specific $(project) : $(root) : arm64-linux : : : + : linux arm static shared ; + + configure-specific $(project) : $(root) : ppc64le-linux : : : + : linux power static shared ; + + configure-specific $(project) : $(root) : riscv32-linux : : : + : linux 32 riscv static shared ; + + configure-specific $(project) : $(root) : riscv64-linux : : : + : linux riscv static shared ; + + configure-specific $(project) : $(root) : s390x-linux : : : + : linux s390x static shared ; + + # Windows + configure-specific $(project) : $(root) : x64-windows : : : + : windows shared shared desktop ; + configure-specific $(project) : $(root) : x64-windows-static : : : + : windows static static desktop ; + configure-specific $(project) : $(root) : x64-windows-static-md : : : + : windows static shared desktop ; + + configure-specific $(project) : $(root) : x86-windows : : : + : windows 32 shared shared desktop ; + configure-specific $(project) : $(root) : x86-windows-static-md : : : + : windows 32 static shared desktop ; + configure-specific $(project) : $(root) : x86-windows-static : : : + : windows 32 static static desktop ; + + configure-specific $(project) : $(root) : arm64-windows : : : + : windows arm shared shared desktop ; + configure-specific $(project) : $(root) : arm64-windows-static-md : : : + : windows arm static shared desktop ; + configure-specific $(project) : $(root) : arm64-windows-static : : : + : windows arm static static desktop ; + + configure-specific $(project) : $(root) : arm-windows : : : + : windows 32 arm shared shared desktop ; + configure-specific $(project) : $(root) : arm-windows-static : : : + : windows 32 arm static static desktop ; + + # WindowsStore + configure-specific $(project) : $(root) : x64-uwp : : : + : windows shared shared store ; + configure-specific $(project) : $(root) : x64-uwp-static-md : : : + : windows static shared store ; + + configure-specific $(project) : $(root) : x86-uwp : : : + : windows 32 shared shared store ; + configure-specific $(project) : $(root) : x86-uwp-static-md : : : + : windows 32 static shared store ; + + configure-specific $(project) : $(root) : arm64-uwp : : : + : windows arm shared shared store ; + configure-specific $(project) : $(root) : arm64-uwp-static-md : : : + : windows arm static shared store ; + + configure-specific $(project) : $(root) : arm-uwp : : : + : windows 32 arm shared shared store ; + configure-specific $(project) : $(root) : arm-uwp-static-md : : : + : windows 32 arm static shared store ; + + # OSX + configure-specific $(project) : $(root) : x64-osx : : : + : darwin static shared ; + configure-specific $(project) : $(root) : x64-osx-dynamic : : : + : darwin shared shared ; + + configure-specific $(project) : $(root) : arm64-osx-dynamic : : : + : darwin arm shared shared ; + configure-specific $(project) : $(root) : arm64-osx : : : + : darwin arm static shared ; + + # Android + configure-specific $(project) : $(root) : x64-android : : : + : android static static ; + + configure-specific $(project) : $(root) : x86-android : : : + : android 32 static static ; + + configure-specific $(project) : $(root) : arm64-android : : : + : android arm static static ; + + configure-specific $(project) : $(root) : arm-android : : : + : android 32 arm static static ; + + # iPhone + configure-specific $(project) : $(root) : arm-ios : : : + : iphone 32 arm static shared ; + + configure-specific $(project) : $(root) : arm64-ios : : : + : iphone arm static shared ; + + configure-specific $(project) : $(root) : x64-ios : : : + : iphone static shared ; + + configure-specific $(project) : $(root) : x86-ios : : : + : iphone 32 static shared ; + + # FreeBSD + configure-specific $(project) : $(root) : x64-freebsd : : : + : freebsd static shared ; + + configure-specific $(project) : $(root) : x86-freebsd : : : + : freebsd 32 static shared ; + + # OpenBSD + configure-specific $(project) : $(root) : x64-openbsd : : : + : openbsd static shared ; + +} + +local rule configure-specific ( project : root ? : triplet ? : prefix ? + : incdir ? : libdir ? : requirements + ) +{ + if ! $(incdir) || ! $(libdir) + { + if ! $(prefix) + { + prefix = [ deduce-prefix $(root) : $(triplet) ] ; + } + incdir ?= [ path.join $(prefix) include ] ; + libdir ?= [ path.join $(prefix) lib ] ; + if ! [ property.select : $(requirements) ] + { + with-debug = true ; + } + } + + if with-debug + { + declare-target $(project) : $(incdir) : $(libdir) + : $(requirements) release ; + declare-target $(project) : $(incdir) + : [ path.join $(prefix) debug/lib ] + : $(requirements) debug ; + } + else + { + declare-target $(project) : $(incdir) : $(libdir) : $(requirements) ; + } +} + +local rule declare-target ( project : incdir : libdir : requirements * ) +{ + if $(.debug) + { + echo "notice: [vcpkg] configuring with" $(incdir) + $(libdir) ; + } + + targets.create-metatarget alias-target-class + : $(project) + : prefix + : + : $(requirements) + : + : $(incdir) + $(libdir) + ; +} + +local rule deduce-prefix ( root ? : triplet ? ) +{ + if ! $(root) + { + root = [ deduce-root ] ; + } + + triplet ?= [ os.environ VCPKG_DEFAULT_TRIPLET ] ; + if ! $(triplet) && $(root) + { + local ignored = [ path.join $(root) vcpkg ] ; + for local p in [ path.glob $(root) : * ] + { + if $(p) != $(ignored) + { + triplet += $(p:B) ; + } + } + if $(triplet[2]) + { + triplet = ; + } + } + + if ! $(root) || ! $(triplet) + { + errors.user-error "could not initialize vcpkg module:" + "vcpkg installation could not be deduced" ; + } + + return [ path.join $(root) $(triplet) ] ; +} + +local rule deduce-root ( ) +{ + # attempt to locate vcpkg installation using environment variable + local root = [ os.environ VCPKG_ROOT ] ; + if $(root) + { + root = [ path.join [ path.make $(root) ] installed ] ; + } + else + { + # check if Manifest mode is used + local roots = . [ path.all-parents . ] ; + while $(roots) && ! $(root) + { + if [ path.glob $(roots[1]) : vcpkg.json ] + { + root = $(roots[1])/vcpkg_installed ; + } + roots = $(roots[2-]) ; + } + } + + return $(root) ; +}