[CMake] Generator Expressions and FetchContent

Saad Khattak saadrustam at gmail.com
Mon Mar 19 08:51:18 EDT 2018


I do use target_link_libraries when it comes to C++ projects and it works
wonderfully for them. However, in this case, my base project has a bunch of
helper files with CMake functionality that help me work with and build my
library of projects (which you can see here
https://github.com/2LoC/tl_base_ci).

Of course, these helper .cmake files (with the functionality I want) are in
the tl_base_ci project which can be either (1) cloned separately, built,
(2) Installed without building, or (3) cloned through ExternalProject_Add
(which I am trying to convert to FetchContent). In all cases, the include
directories might differ, which is why I use rely on the generator
expressions expanding.

In projects depending on tl_base_ci (e.g.
https://github.com/2LoC/tl_proj_template), I have CMake includes like this:

include("${tl_base_ci_INCLUDE_DIRECTORY}/tl_base_ci/tl_common.cmake") # in
the actual project, it's slightly different as it searches for the file in
a list of directories returned by
get_target_property(... INTERFACE_INCLUDE_DIRECTORIES)

Where the tl_base_ci_INCLUDE_DIRECTORY might differ. So ultimately I was
hoping for a way to reliably include the helper .cmake files (i.e. figure
out tl_base_ci's include directory path). I did that with
get_target_property(...) which worked great for ExternalProject_Add, but
did not work so well for FetchContent because the generator expressions did
not expand.

Hopefully I was able to explain the problem well. If there is any
confusion, please let me know.



On Mon, Mar 19, 2018 at 7:11 AM Craig Scott <craig.scott at crascit.com> wrote:

> On Mon, Mar 19, 2018 at 8:25 AM, Saad Khattak <saadrustam at gmail.com>
> wrote:
>
>> Thank you for the clarification Craig.
>>
>> >> If you made your main target link against LibA, you'd see that CMake
>> automatically expands out the generator expressions when it constructs the
>> link command line for main, so the example as it stands doesn't actually
>> have any error.
>>
>> In my actual project, a library like LibA has .cmake files that can be
>> included by dependent projects to reuse. Of course, CMake `include` does
>> not get affected by target_link_libraries.
>>
>> I would like dependent projects to have the ability to use an existing
>> clone of LibA, if found (e.g. using find_package), otherwise clone locally
>> for using ExternalProject_Add which I am now trying to refactor to
>> FetchContent. Another option open to dependent projects is to force the
>> FetchContent on all repositories regardless of what find_package returns
>> (this is great for testing locally to ensure I have no uncommitted,
>> unpushed changes).
>>
>> Using existing clones is a way to ensure that every project dependent on
>> LibA doesn't clone it's own copy (unless forced to do so).
>>
>> To allow the possibility for any dependent project to include the .cmake
>> files properly, I get the INTERFACE_INCLUDE_DIRECTORIES target property
>> (using get_target_property) for LibA and then include the .cmake utility
>> files like this:
>>
>> include(${LibA_INCLUDE_DIRECTORY}/my_utility.cmake)
>>
>> Perhaps I am approaching the problem incorrectly? Essentially, I would
>> like a way to reliably include .cmake files found in LibA's include folder
>> regardless of how LibA was acquired (e.g. cloned and built and/or installed
>> separately or acquired using FetchContent). In my case, I could only think
>> of the above as a reliable way to include the files.
>>
>
> Rather than focusing on including files, I would choose to base things
> around targets. If the rest of your project simply links against the
> required target name, the target itself should bring with it any transitive
> dependencies such as required header search paths, dependent libraries that
> must also be linked, etc. These are the INTERFACE_... properties that can
> be set on a target, usually by commands such as
> target_include_directories(foo INTERFACE ...), target_link_libraries(foo
> INTERFACE ...), etc. When building directly from your source tree, the
> targets will be directly available. When using find_package(), the package
> should provide import targets. The rest of your project shouldn't really
> need to care which one of the two it is dealing with. This is the
> recommended way to structure a situation like this. You shouldn't need to
> also pull in a secondary .cmake file in most circumstances, but maybe I'm
> missing something about your particular situation.
>
>
>
>>
>> On Sun, Mar 18, 2018 at 4:22 PM Craig Scott <craig.scott at crascit.com>
>> wrote:
>>
>>> On Mon, Mar 19, 2018 at 3:44 AM, Saad Khattak <saadrustam at gmail.com>
>>> wrote:
>>>
>>>> Absolutely. Please find the example project here:
>>>> https://github.com/samaursa/cmake_fetch_content_and_generator_expressions
>>>>
>>>>
>>>> The repository README also includes the output from running
>>>> `./setup.sh`.
>>>>
>>>
>>>
>>> Okay that's much clearer, thanks. The example is doing what I'd expect
>>> and the generator expressions are also expected to be visible at the point
>>> your example is printing them. If you made your main target link
>>> against LibA, you'd see that CMake automatically expands out the
>>> generator expressions when it constructs the link command line for main,
>>> so the example as it stands doesn't actually have any error.
>>>
>>> Generator expressions are not expanded when CMake is processing the
>>> files (called the *configure* stage), they are expanded only when
>>> writing out the Makefiles during the *generation* stage. When running
>>> cmake from the command line, one doesn't tend to think of these two phases
>>> as being distinct, but you can see it at the end of the cmake log with
>>> these two messages:
>>>
>>> -- Configuring done
>>> -- Generating done
>>>
>>> It is clearer when using the CMake GUI application because you get two
>>> different buttons, one for Configure and another for Generate, so you have
>>> to trigger both phases manually. So if you look at the contents of various
>>> properties and variables with CMake commands like message(...), you are
>>> doing that during the configure stage and therefore will see unexpanded
>>> generator expressions.
>>>
>>>
>>>
>>>
>>>>
>>>> On Sat, Mar 17, 2018 at 6:47 PM Craig Scott <craig.scott at crascit.com>
>>>> wrote:
>>>>
>>>>> Can you provide a small project example that can be used to
>>>>> demonstrate your problem? The specifics of how you are doing things may be
>>>>> important.
>>>>>
>>>>>
>>>>> On Sun, Mar 18, 2018 at 8:12 AM, Saad Khattak <saadrustam at gmail.com>
>>>>> wrote:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> ExternalProject_Add builds, generates and installs and thus any
>>>>>> generator expressions used will be expanded by the time another library
>>>>>> uses it.
>>>>>>
>>>>>> For example, if I add a library LibA using ExternalProject_Add, I can
>>>>>> then query the target property INTERFACE_INCLUDE_DIRECTORIES and get the
>>>>>> include directory for the library:
>>>>>>
>>>>>> get_target_property(LibA_INCLUDE_DIRECTORIES LibA
>>>>>>   INTERFACE_INCLUDE_DIRECTORIES
>>>>>>   )
>>>>>>
>>>>>> This allows me to then use the variable LibA_INCLUDE_DIRECTORIES in
>>>>>> my CMake include(...) statements. However, with FetchContent, this is no
>>>>>> longer possible.
>>>>>>
>>>>>> The reason I would like to query a variable is because at project
>>>>>> generation time, I invoke FetchContent only if LibA is not found by
>>>>>> find_package(LibA).
>>>>>>
>>>>>> Thus, the include directory for LibA may be in the current build
>>>>>> directory (through FetchContent) OR it may be found in the folder where
>>>>>> LibA is cloned by the user and generated/built OR an INSTALL of LibA.
>>>>>>
>>>>>> Perhaps I should not be using `get_target_property` to get the a
>>>>>> library's include directory? Either way, would like some guidance in
>>>>>> solving this issue.
>>>>>>
>>>>>> Thank you,
>>>>>> Saad
>>>>>>
>>>>>
>>>
>
>
> --
> Craig Scott
> Melbourne, Australia
> https://crascit.com
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://cmake.org/pipermail/cmake/attachments/20180319/7501cdde/attachment-0001.html>


More information about the CMake mailing list