Installing CMake configuration files
I've taken another stab at installing CMake configuration files along with the libraries in `b2 install`. CMake configuration files are .cmake files, typically installed into $prefix/lib or $prefix/lib/cmake, that allow f.ex. `find_package(boost_system)` in a CMakeLists.txt file to find the installed Boost.System library and declare a CMake target Boost::system that refers to it. CMake targets can then link to Boost::system and all is well. The work in its current state is available on the feature/cmake-config branch of the superproject: git clone --recursive -b feature/cmake-config https://github.com/boostorg/boost cd boost bootstrap b2 --prefix=... install After that .../lib should contain the libraries and .../lib/cmake - the config files. Then from CMake cmake -DCMAKE_INSTALL_PREFIX=... .. as usual. See for example the test scripts at https://github.com/boostorg/boost_install/blob/master/.travis.yml#L60 and https://github.com/boostorg/boost_install/blob/master/appveyor.yml#L40 Since `b2 install` installs more than one library variant, the CMake configurations need to pick the correct one and to do so look at (a subset of) the FindBoost-compatible variables as described at: https://github.com/Kitware/CMake/blob/master/Modules/FindBoost.cmake#L122 Boost_USE_DEBUG_LIBS, Boost_USE_RELEASE_LIBS, Boost_USE_STATIC_LIBS, Boost_USE_STATIC_RUNTIME, Boost_COMPILER, Boost_DEBUG are honored and have the same meaning as in FindBoost. Boost_USE_MULTITHREADED and Boost_USE_DEBUG_RUNTIME are presently ignored, but probably shouldn't be. :-) The default of Boost_USE_STATIC_LIBS being OFF is a bit inconvenient on Windows, where without `--build-type=complete` our installation only gives you static libraries, and there are suggestions to respect it being ON or OFF, but when not set, to look at BUILD_SHARED_LIBS instead. Under the hood this represents a refactoring of the current centralized installation approach in which the superproject staged and installed the libraries on `b2 stage` and `b2 install`. Now the top level stage and install targets just delegate to each library's stage and install targets, which are responsible for staging/installing that particular library, its CMake config, and its dependencies. These library-level stage and install targets are created by the helper b2 rule boost-install, which already existed (in Jamroot), but is now much enhanced and lives in its own module tools/boost_install. In addition, a metalibrary libs/headers is introduced, which corresponds to the headers as present in a release (in subdirectory boost/) or as installed by `b2 install`. Its install target, in fact, installs the headers, and its stage target, currently empty, should probably assume the function of linking the headers (which at the moment also lives in Jamroot.) At some future point, when we decide to switch to releasing the headers in their original libs/$lib/include locations, the install target of a library will just copy that library's headers; but we aren't there yet. The header-only libraries are used from CMake by finding the package boost_headers and linking to the target Boost::headers. I've deliberately not done anything about Boost::boost and find_package(Boost), to allow FindBoost.cmake to delegate to the config files if present (when Boost 1.69/1.70 or higher is installed), while preserving backward compatibility (when 1.68 or lower is installed.)
On Fri, Oct 12, 2018 at 8:01 PM Peter Dimov via Boost
I've taken another stab at installing CMake configuration files along with the libraries in `b2 install`. CMake configuration files are .cmake files, typically installed into $prefix/lib or $prefix/lib/cmake, that allow f.ex. `find_package(boost_system)` in a CMakeLists.txt file to find the installed Boost.System library and declare a CMake target Boost::system that refers to it. CMake targets can then link to Boost::system and all is well.
Neat!!!
[...]
The header-only libraries are used from CMake by finding the package boost_headers and linking to the target Boost::headers. I've deliberately not done anything about Boost::boost and find_package(Boost), to allow FindBoost.cmake to delegate to the config files if present (when Boost 1.69/1.70 or higher is installed), while preserving backward compatibility (when 1.68 or lower is installed.)
Would it be possible to have one Boost::XYZ library for each header-only library XYZ? Those would just include the headers by default, however it has the following benefits from the user side: 1. If a library stops being header-only, user code still works and will automatically start linking against the right library when the CMake Config file is updated. 2. It allows providing compile options or required compile features via the imported target. For example, I may want someone "linking" against Boost::hana to get `-Wno-user-defined-literal` automatically (I don't, but you get the idea). Louis
Louis Dionne wrote:
Would it be possible to have one Boost::XYZ library for each header-only library XYZ?
It's possible in principle; my first iteration did have targets for all libraries. I'd however prefer to get a release out using this scheme first, to see how it fares in the field. There are several possible approaches we could adopt if we want targets for all libraries, and the one I like is to go full modular and add build/Jamfiles to header-only libraries, with stage and install targets that link/copy the headers. So that you could `b2 --prefix=~/.local install-hana` from top level and get, in ~/.local/include, Hana's headers and the headers of its dependencies, and in ~/.local/lib/cmake, the config files of same. For this to work, we need to change our releases to no longer delete libs/$lib/include, as I mentioned. Also, we need to fix our circular dependencies. This may take a while. :-) It's not clear whether all this will be worth doing if we're going to move to a CMake-based installation though.
Those would just include the headers by default, however it has the following benefits from the user side:
1. If a library stops being header-only, user code still works and will automatically start linking against the right library when the CMake Config file is updated.
2. It allows providing compile options or required compile features via the imported target. For example, I may want someone "linking" against Boost::hana to get `-Wno-user-defined-literal` automatically (I don't, but you get the idea).
How are you going to communicate your target_compile_definitions (or whatever) to the code generating the config file? Perhaps you'll have a ready-made config file that would be installed instead of the generated one?
AMDG On 10/15/2018 09:20 PM, Peter Dimov via Boost wrote:
Louis Dionne wrote:
<snip> 2. It allows providing compile options or required compile features via the imported target. For example, I may want someone "linking" against Boost::hana to get `-Wno-user-defined-literal` automatically (I don't, but you get the idea).
How are you going to communicate your target_compile_definitions (or whatever) to the code generating the config file? Perhaps you'll have a ready-made config file that would be installed instead of the generated one?
It's probably possible to handle this by translating (a subset of) the usage-requirements from the library. In Christ, Steven Watanabe
AMDG On 10/15/2018 09:20 PM, Peter Dimov via Boost wrote:
Louis Dionne wrote:
Would it be possible to have one Boost::XYZ library for each header-only library XYZ?
It's possible in principle; my first iteration did have targets for all libraries. I'd however prefer to get a release out using this scheme first, to see how it fares in the field.
There are several possible approaches we could adopt if we want targets for all libraries, and the one I like is to go full modular and add build/Jamfiles to header-only libraries, with stage and install targets that link/copy the headers. So that you could `b2 --prefix=~/.local install-hana` from top level and get, in ~/.local/include, Hana's headers and the headers of its dependencies, and in ~/.local/lib/cmake, the config files of same.
+1
For this to work, we need to change our releases to no longer delete libs/$lib/include, as I mentioned.
It's not strictly necessary, as long as there's some way to enumerate the headers belonging to a specific library. (Obviously doing a glob-tree in libs/$lib/include is the most convenient way to do so.)
Also, we need to fix our circular dependencies. This may take a while. :-)
It might be easier in the short term to make Boost.Build handle circular dependencies (in some cases). I already have a pretty good idea of how to do it, as I implemented support for circular #includes in the jam scanner. The required semantics in this case are pretty simple: If any library in the cycle is installed/staged, then all of them are. In Christ, Steven Watanabe
On Mon, Oct 15, 2018 at 11:53 PM Steven Watanabe via Boost < boost@lists.boost.org> wrote:
AMDG It might be easier in the short term to make Boost.Build handle circular dependencies (in some cases). I already have a pretty good idea of how to do it, as I implemented support for circular #includes in the jam scanner.
The required semantics in this case are pretty simple: If any library in the cycle is installed/staged, then all of them are.
Although we had to it manually, that's the way we "solved" it for the Conan modular packaging also. We no longer do it manually as I have a script that generates the circular groups from boostdep information. -- -- Rene Rivera -- Grafik - Don't Assume Anything -- Robot Dreams - http://robot-dreams.net
On 10/15/18 11:20 PM, Peter Dimov via Boost wrote:
Louis Dionne wrote:
Would it be possible to have one Boost::XYZ library for each header-only library XYZ?
It's possible in principle; my first iteration did have targets for all libraries. I'd however prefer to get a release out using this scheme first, to see how it fares in the field.
Wait. Are you saying you first want to get a Boost release out that's entirely built with CMake, but built monolithically as in the past ? Either you haven't paid any attention to the discussions on this list over recent years, or you expressly ignore the opinions voiced by the participants. Which is it ? Stefan -- ...ich hab' noch einen Koffer in Berlin...
-----Original Message----- From: Boost
On Behalf Of Stefan Seefeld via Boost Sent: Tuesday, October 16, 2018 1:35 PM On 10/15/18 11:20 PM, Peter Dimov via Boost wrote:
Louis Dionne wrote:
Would it be possible to have one Boost::XYZ library for each header-only library XYZ?
It's possible in principle; my first iteration did have targets for all libraries. I'd however prefer to get a release out using this scheme first, to see how it fares in the field.
Wait. Are you saying you first want to get a Boost release out that's entirely built with CMake, but built monolithically as in the past ?
Either you haven't paid any attention to the discussions on this list over recent years, or you expressly ignore the opinions voiced by the participants. Which is it ?
No need to fetch your pitchfork just yet. As far as I can tell, Peter didn't mention building boost with cmake anywhere. Just letting b2 auto generate the config files that allow cmake projects to use an installed boost library. I guess what Peter meant (please correct me if I'm wrong) was that he wanted test that mechanism with a real boost release before adding more features to it (if at all). Mike
Stefan Seefeld wrote:
Wait. Are you saying you first want to get a Boost release out that's entirely built with CMake, but built monolithically as in the past ?
No. This is about installing CMake support files as part of the existing `b2 install` such that the so-installed Boost can be used from CMake projects. Roughly speaking, this consists of teaching Boost.Build to install libboost_foo.cmake alongside libboost_foo.a.
On 10/17/18 6:11 PM, Peter Dimov via Boost wrote:
Stefan Seefeld wrote:
Wait. Are you saying you first want to get a Boost release out that's entirely built with CMake, but built monolithically as in the past ?
No. This is about installing CMake support files as part of the existing `b2 install` such that the so-installed Boost can be used from CMake projects.
Roughly speaking, this consists of teaching Boost.Build to install libboost_foo.cmake alongside libboost_foo.a.
OK, that's not as bad as I had feared. :-) [ I'm very happy to see some effort being put into modularization, but I do wonder why we couldn't do the same for Boost.Build itself. That is, I'd like to be able to declare explicitly in my Jamfile that my project X depends on project Y and Z, which should be enough to pull in all "usage requirements" (including include and library search paths) from those prerequisites, so no matter where they are (in the same source tree or pre-built and installed), I can run the build. ] Stefan -- ...ich hab' noch einen Koffer in Berlin...
On Wed, Oct 17, 2018 at 5:19 PM Stefan Seefeld via Boost < boost@lists.boost.org> wrote:
[ I'm very happy to see some effort being put into modularization, but I do wonder why we couldn't do the same for Boost.Build itself. That is, I'd like to be able to declare explicitly in my Jamfile that my project X depends on project Y and Z, which should be enough to pull in all "usage requirements" (including include and library search paths) from those prerequisites, so no matter where they are (in the same source tree or pre-built and installed), I can run the build. ]
We can do that.. And I've been moving towards doing that for more than a decade. But we've been sufficiently married to the monolithic development for so long that it's painful to make those changes. And again, it's not the build system at fault, b2 supports such modularity. And what I argue in the cmake thread is that we *must* do that for the sake of being able to easily support our users and the future of Boost. -- -- Rene Rivera -- Grafik - Don't Assume Anything -- Robot Dreams - http://robot-dreams.net
On Mon, Oct 15, 2018 at 8:20 PM Peter Dimov via Boost
Louis Dionne wrote:
Would it be possible to have one Boost::XYZ library for each header-only library XYZ?
It's possible in principle; my first iteration did have targets for all libraries. I'd however prefer to get a release out using this scheme first, to see how it fares in the field.
Ok, I agree with that approach.
There are several possible approaches we could adopt if we want targets for all libraries, and the one I like is to go full modular and add build/Jamfiles to header-only libraries, with stage and install targets that link/copy the headers. So that you could `b2 --prefix=~/.local install-hana` from top level and get, in ~/.local/include, Hana's headers and the headers of its dependencies, and in ~/.local/lib/cmake, the config files of same.
That would be great.
[...]
2. It allows providing compile options or required compile features via
the imported target. For example, I may want someone "linking" against Boost::hana to get `-Wno-user-defined-literal` automatically (I don't, but you get the idea).
How are you going to communicate your target_compile_definitions (or whatever) to the code generating the config file? Perhaps you'll have a ready-made config file that would be installed instead of the generated one?
I see two main options: 1. What you suggest, i.e. a ready-made config file that can be installed through Bjam. 2. Somehow have Bjam call into CMake to install that. I'm fine with (1), at least initially. With your current solution, is there a way to substitute the Config files being automatically generated for Config files of my choice? Louis
Louis Dionne wrote:
With your current solution, is there a way to substitute the Config files being automatically generated for Config files of my choice?
Yes in principle. You can just declare your own `stage` and `install` targets in your build/Jamfile and do whatever you like there. For a header-only library such as Hana, and with our current monolithic ball of headers scheme, that would be easy since `stage` does nothing and `install` just needs to copy the CMake config file to its proper location. For a buildable library, it would be more convoluted since boost-install does a lot of work that would need to be duplicated. (On the other hand, you would rarely need to override the default for buildable libraries.) We'll figure something out, eventually, when we get to that point.
AMDG On 10/12/2018 09:00 PM, Peter Dimov via Boost wrote:
I've taken another stab at installing CMake configuration files along with the libraries in `b2 install`. CMake configuration files are .cmake files, typically installed into $prefix/lib or $prefix/lib/cmake, that allow f.ex. `find_package(boost_system)` in a CMakeLists.txt file to find the installed Boost.System library and declare a CMake target Boost::system that refers to it. CMake targets can then link to Boost::system and all is well.
Just a couple comments: * If generate-cmake-config takes the library as a source, then it's possible to derive both the library dependencies and the exact library name from the library target. The dependencies can be found at the virtual target level in generate-cmake-config, and the exact file name will appear as the source in generate-cmake-config-. Doing it this way also has the side effect that the CMake configuration won't be installed if the library fails to build, which may be a good thing. * I'm not fond of the ROOT parameter for boost-install.boost-install. * Dependencies can be referenced with /boost/$(deps)//[stage|install] * You can find the full path to the boost-install.jam with [ path.root [ modules.binding $(__name__) ] [ path.pwd ] ] This avoids hard-coding the location of boost_install relative to the superproject. * That just leaves the stage directory, which is tied to the project root, and should perhaps be calculated in Jamroot instead of in boost_install. * This seems to handle --layout=versioned, but I'm not clear on how well it handles --layout=system where we expect to use a single compiled library for all configurations. * Are the error messages that you get from CMake when there isn't a configuration that matches the request intelligible? It looks like the target will exist but will silently do nothing? What if something goes wrong and there are multiple matches?
The work in its current state is available on the feature/cmake-config branch of the superproject:
In Christ, Steven Watanabe
participants (6)
-
Louis Dionne
-
Mike Dev
-
Peter Dimov
-
Rene Rivera
-
Stefan Seefeld
-
Steven Watanabe