# CMake project review and suggestions (closed)

**URL:** https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768
**Category:** Code
**Created:** [March 4, 2020, 11:53pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768 "2020-03-04T23:53:59Z")
**Posts on this page:** 15
**Page:** 2

<div class="post-metadata">

### Author: ![hex](https://discourse.cmake.org/user_avatar/discourse.cmake.org/hex/32/363_2.png) [@hex](https://discourse.cmake.org/u/hex)
#### Post date: [May 27, 2020, 12:04pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/21 "2020-05-27T12:04:26Z")

</div>

> [@Artemis](#):
>
> How am I supposed to write CMake code that doesn’t break if some paths have semicolons in them?  
> I mean, that’s a quite common character, I can’t just leave it out.

Good question, I would like to expand on this. here is an example:

```bash
mkdir "build;dir" ; cd "build;dir"
cmake ..

```

leading to:

```auto
CMake Error at /usr/local/share/cmake-3.17/Modules/CMakeDetermineSystem.cmake:173 (file):
  file failed to open for writing (Is a directory):

    ./build
Call Stack (most recent call first):
  CMakeLists.txt:8 (project)

```

it fails at configure stage before loading the language features at line:

```cmake
project( issue768 LANGUAGES NONE )

```

The semicolon `;` is a reserved character in FAT file systems so if it breaks is actually a good thing as using semicolons prevents portability of the project.

also, where did you get the recommendation from to

> [@Artemis](#):
>
> remove all the unnecessary double quotes around variables I kept putting everywhere.

?

---

<div class="post-metadata">

### Author: ![hex](https://discourse.cmake.org/user_avatar/discourse.cmake.org/hex/32/363_2.png) [@hex](https://discourse.cmake.org/u/hex)
#### Post date: [May 27, 2020, 2:13pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/22 "2020-05-27T14:13:06Z")

</div>

> [@Artemis](#):
>
> So that’s because of how functions are designed, right?

Yes. A list is a list, and a list element is a list element. This leads to confusion sometimes.

```cmake
set_target_properties(target1 target2 ...
                      PROPERTIES prop1 value1
                      prop2 value2 ...)

```

does not expect a list for `PROPERTIES`, it expects `value1 ...`

```cmake
foreach(<loop_var> IN [LISTS [<lists>]] )

```

`foreach` expects a list for `LISTS`.

---

<div class="post-metadata">

### Author: ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)
#### Post date: [May 27, 2020, 2:37pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/23 "2020-05-27T14:37:43Z")

</div>

> [@hex](#):
>
> The semicolon `;` is a reserved character in FAT file systems so if it breaks is actually a good thing as using semicolons prevents portability of the project.

Good point, and

> [@hex](#):
>
> it fails at configure stage before loading the language features at line:
> 
> ```auto
> project( issue768 LANGUAGES NONE )
> 
> ```

even better! It means my project won’t be the one preventing that.

> [@hex](#):
>
> ?

Eh you’re right. Nobody told me. I did it because of all the scripts I read online, hardly anyone used quotation marks regularly. Another lesson on how in Cmake is often a bad idea to assume practices from random scripts online. Everyone seems working with it’s personal conception of the language.

> [@hex](#):
>
> This leads to confusion sometimes.

I concur.

---

<div class="post-metadata">

### Author: ![robert.maynard](https://discourse.cmake.org/user_avatar/discourse.cmake.org/robert.maynard/32/4_2.png) [@robert.maynard](https://discourse.cmake.org/u/robert.maynard)
#### Post date: [May 27, 2020, 2:45pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/24 "2020-05-27T14:45:10Z")

</div>

> [@Artemis](#):
>
> How am I supposed to write CMake code that doesn’t break if some paths have semicolons in them?  
> I mean, that’s a quite common character, I can’t just leave it out.

Un-escaped “;” in file paths / strings are not supported by CMake itself. Therefore you really can’t try to support the use case.

---

<div class="post-metadata">

### Author: ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)
#### Post date: [May 31, 2020, 2:19pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/25 "2020-05-31T14:19:47Z")

</div>

I can’t understand what is the difference between the `exporto()` command EXPORT and the `EXPORT` argument to the `install()` command. I’ve read the `install()` documentation page:

> `EXPORT`  
> This option associates the installed target files with an export called `<export-name>` . It must appear before any target options. To actually install the export file itself, call install(EXPORT)

and

> The `EXPORT` form generates and installs a CMake file containing code to import targets from the installation tree into another project. **Target installations are associated with the export `<export-name>` using the `EXPORT` option of the install(TARGETS) signature documented above.**

What I got from here, is that I can group targets in named “exports”. (I’ll call them “export groups”, like I did in the very first post). I still don’t know what to do with this grouping feature, so I’ll stick to one for now. I haven’t seen a project that uses more than one export groups yet.

An export group translates to a generated file (usually called `<export-name>.cmake`) which contains CMake code to “import” the targets in the export group. (it basically mirrors everything with an `IMPORTED` flag? I’m not sure of what it does exactly).  
This step is done by the `install(EXPORT <export-name> ...` command.

This is what I understood from the documentation. But I’m not using just the documentation because it mostly says how things work, not how you should actually proceed to `do the things`. So, I’ve read [this nice article](https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/#this-is-how-you-do-cmake), which was recommended and praised by a lot of people.  
He calls:

```cmake
install(TARGETS JSONUtils
    EXPORT jsonutils-export # creates an export group called "jsonutils-export"
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

```

and

```cmake
install(EXPORT jsonutils-targets # I don't know what "jsonutils-targets" is
  FILE
    JSONUtilsTargets.cmake 
    ...

```

I understand that I didn’t understand. And I still don’t understand.

---

<div class="post-metadata">

### Author: ![hex](https://discourse.cmake.org/user_avatar/discourse.cmake.org/hex/32/363_2.png) [@hex](https://discourse.cmake.org/u/hex)
#### Post date: [May 31, 2020, 3:41pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/27 "2020-05-31T15:41:47Z")

</div>

The reason why the targets are `IMPORTED` is because they are part of another CMake project. Therefore, they do not need to be compiled by the consuming project. For imported targets, the build step is skipped and their build artifacts are not removed on clean.

Install targets installs your targets. The options `EXPORT jsonutils-export` **additionally** registers your targets for CMake. Install export creates a file for `jsonutils-targets` which contains all registered targets. The resulting file from this process can then be used in consuming CMake projects.

A very comprehensive explanation on the difference between using export directly vs installing an export is given in the book “Professional CMake”. It is very comprehensive in general and a lot easier than guiding yourself from the online documentation and what else you can find on the internet.

---

<div class="post-metadata">

### Author: ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)
#### Post date: [May 31, 2020, 6:00pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/28 "2020-05-31T18:00:52Z")

</div>

> [@hex](#):
>
> Install targets installs your targets. The options `EXPORT jsonutils-export` **additionally** registers your targets for CMake.

Exactly

> [@hex](#):
>
> Install export creates a file for `jsonutils-targets` which contains all registered targets.

Shouldn’t the `<export-name>` parameter be the name of the export group we want to write to file? (yes it’s also used as file name, except if specified otherwise)

> By default the generated file will be called `<export-name>.cmake` but the `FILE` option may be used to specify a different name.

We should specify to `install(EXPORT)` what export group to install, somehow. If not with `<export-name>`, how?

### Edit

Nevermind (#･\_･#). I’ve discovered the article had a comment section that didn’t load till now. It was a mistake on the article. It seems there are even more mistakes left there. I made you waste time for nothing, I’m sorry.

  

> [@hex](#):
>
> A very comprehensive explanation on the difference between using export directly vs installing an export is given in the book “Professional CMake”.

I’ll tell you, I’m actually a book guy. Reading manuals can be a pain, but I’m not really a fan of learning by doing. I think that if a tool has many ways to do something, there’s always one that does what you need the best. And the only way to have that kind of awareness is to read a good book.  
But in this case I was strongly advised against picking up a CMake book, because everyone has different “modernity” in their modern CMake, and because they often came in conflict with the documentation itself (by promoting old/inefficient practices or by skipping features entirely).  
I’m now of the idea that I should’ve picked up a good one and proceed from that, but what is done is done, and now I don’t have the time to start anew, maybe in the future. So here I am :]

---

<div class="post-metadata">

### Author: ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)
#### Post date: [June 1, 2020, 1:33pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/29 "2020-06-01T13:33:19Z")

</div>

How do you install and export a custom target? I was pondering.  
You don’t, because as it’s said [here](https://gitlab.kitware.com/cmake/cmake/-/issues/16990), a custom target exists to define a shared build step, usable by other targets. If you have a custom target that generates files that need to be installed, you use `install(FILES` or `install(DIRECTORY`. No export group involved and of course no `IMPORTED` targets are generated. What would the user’s CMake do with those loose files anyway?

That said, I need to install the project’s documentation. The docs building pipeline is composed, as now, of three custom targets: `doxygen_generate_xml`, `sphinx_generate_html` (created by the respective find modules), and `documentation`. Each of these targets depends on the previous one.

I initially thought that when a target was installed with `install(TARGETS`, CMake would only build the specified targets. Instead, I’ve read that it builds for “ALL”. (otherwise custom targets couldn’t be built!)

I’ve seen that the `doxygen_generate_xml` and `sphinx_generate_html` targets have both the `ALL` flag enabled by their find modules. My idea was to have just `documentation` with the `ALL` flag, and have everything below built automatically as dependencies. What does CMake exactly do if each of them have the flag enabled? Does it still follow the correct build order?

The approach used in the [article here](https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/) is different. She creates a `custom_command`, which has the added bonus of being able to run only if the files have changed.  
I’m not really happy of leaving the target-based dependencies approach for a file-based one.  
Like [it’s said here](https://stackoverflow.com/questions/11971917/why-does-cmake-make-a-distinction-between-a-target-and-a-command), I see the `custom_command` as a way to add a step to the build process of one target, without creating a dependant custom target to do that.  
That’s is the only usage I see that doesn’t break the target-based approach. I dunno.

---

<div class="post-metadata">

### Author: ![hex](https://discourse.cmake.org/user_avatar/discourse.cmake.org/hex/32/363_2.png) [@hex](https://discourse.cmake.org/u/hex)
#### Post date: [June 1, 2020, 2:49pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/30 "2020-06-01T14:49:23Z")

</div>

> [@Artemis](#):
>
> Instead, I’ve read that it builds for “ALL”. (otherwise custom targets couldn’t be built!)

You are correct, the install has a dependency to `ALL`. Custom targets can be build regardless of the targets `ALL` or `install`, though.

> [@Artemis](#):
>
> What does CMake exactly do if each of them have the flag enabled? Does it still follow the correct build order?

It’s not a flag, it’s an option. CMake defines build orders. As long as you do not accidentally set cyclic dependencies CMake honors all dependencies.

> [@Artemis](#):
>
> I’m not really happy of leaving the target-based dependencies approach for a file-based one.

Not sure what you mean. You have file level dependencies and target level dependencies. **You** decide which is which, then implement in CMake accordingly.

> [@Artemis](#):
>
> That’s is the only usage I see that doesn’t break the target-based approach. I dunno.

Again, this is **your** design decision. CMake provides support for both.

---

<div class="post-metadata">

### Author: ![hex](https://discourse.cmake.org/user_avatar/discourse.cmake.org/hex/32/363_2.png) [@hex](https://discourse.cmake.org/u/hex)
#### Post date: [June 1, 2020, 3:06pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/31 "2020-06-01T15:06:55Z")

</div>

> [@Artemis](#):
>
> How do you install and export a custom target? I was pondering.
> 
> That said, I need to install the project’s documentation.

I might be wrong, but it is my understanding that an installation places build artifacts on the right destination.

Therefore, in the case of documentation all you need is a list of folders and files, and where to put them. So, `install( TARGET ... )` is not the correct form to use here. It is not like you are trying to _execute_ your documentation. Use `install( DIRECTORY ... )`, instead.

---

<div class="post-metadata">

### Author: ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)
#### Post date: [June 1, 2020, 4:54pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/32 "2020-06-01T16:54:18Z")

</div>

> [@hex](#):
>
> Custom targets can be build regardless of the targets `ALL` or `install` , though.

True, bad phrasing, I meant “otherwise standalone custom targets couldn’t be _installed_, because `install(TARGETS` doesn’t accept them”.

> [@hex](#):
>
> As long as you do not accidentally set cyclic dependencies CMake honors all dependencies.

Mmm, still a bit weird to me how it does that. It would pick the targets at the top of the dependency chains first, and then the remaining. Or something like that. Sounds complicated, but oh well. 🙂

> [@hex](#):
>
> So, `install( TARGET ... )` is not the correct form to use here. It is not like you are trying to _execute_ your documentation.

Yes, that’s what I was saying. And even more importantly, it’s not like _CMake_ is going to do anything with the built documentation.

> [@hex](#):
>
> You have file level dependencies and target level dependencies. **You** decide which is which, then implement in CMake accordingly.

yes, I was putting it through the “targets good everything else bad” philosophy. I don’t know whether doing both is wise or bad practice anymore. I like “targets good everything else bad” tho

In fact, I was thinking about making a custom command that launches a build of `documentation` when the files are changed. But since I’m forced to set `ALL` to `documentation` (or it could potentially [cause undefined behaviour](https://cmake.org/cmake/help/v3.16/prop_tgt/EXCLUDE_FROM_ALL.html)), that would be pointless.  
I think that custom targets could benefit from a “last modified check” too, like standard targets do. And like custom commands do. I wonder why they choose force the “always outdated” mechanic.

---

<div class="post-metadata">

### Author: ![hex](https://discourse.cmake.org/user_avatar/discourse.cmake.org/hex/32/363_2.png) [@hex](https://discourse.cmake.org/u/hex)
#### Post date: [June 1, 2020, 5:22pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/33 "2020-06-01T17:22:33Z")

</div>

custom targets cannot be installed, ever. Installing custom targets is bad practice.

If CMake is going to do anything always use exports instead of installs.

> [@Artemis](#):
>
> In fact, I was thinking about making a custom command that launches a build of `documentation` when the files are changed. But since I’m forced to set `ALL` to `documentation` (or it could potentially [cause undefined behaviour](https://cmake.org/cmake/help/v3.16/prop_tgt/EXCLUDE_FROM_ALL.html)), that would be pointless.

This is the correct way of doing it. You define a custom target without `ALL` and add a dependency to a custom command. That command generates output products every time source files have changed.

---

<div class="post-metadata">

### Author: ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)
#### Post date: [June 2, 2020, 9:10pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/34 "2020-06-02T21:10:00Z")

</div>

I didn’t know `add_custom_command(OUTPUT` could accept targets as `DEPENDS`, I thought only `add_custom_command(TARGET` could.  
…one of the first things you see is “Use the `add_dependencies()` command to add dependencies between top-level targets.”, “use `DEPENDS` to specify file dependencies”.  
It’s even quite buried in the description.

> [@Artemis](#):
>
> I’m not really happy of leaving the target-based dependencies approach for a file-based one.  
> Like it’s said here, I see the `custom_command` as a way to add a step to the build process of one target, without creating a dependant custom target to do that.

That’s why I was saying I liked only the second signature, because I thought it was like the first, but for targets.  
How I see them now is: the first signature creates basically a custom target on steroids, without properties and without the word “target”. They can do everything custom targets can, and more. But they exist as separate things. Why? I get _how_ they differ, but not _why_.

The second signature is nice tho. Seems useful to avoid creating too many custom targets that perform setup steps before building a target.

* * *

Having said that, you suggested to create a “loose” (without `ALL`) custom target dependant on a custom command, to get the best of both worlds. The only way I know of making a custom target dependant on a custom command is to have them both in the same file (ok in this case), and to list in the target’s `DEPENDS` some files in the command’s `OUTPUT`.

```cmake
set(watched_files "fileA" "fileB" "fileC") # source and configuration files that could cause a change in the documentation
build_command(sphinx_generate_html_command
              TARGET sphinx_generate_html)
add_custom_target(documentation
                  DEPENDS "${watched_files}")
add_custom_command(OUTPUT "${watched_files}"
                   COMMAND "sphinx_generate_html_command")

```

But what happens if I download the project and install? As far as I know “undefined behaviour”, because `documentation` doesn’t get built (no `ALL`).  
Also, the command doesn’t _personally_ create any output, the custom targets in the dependency chain do. And to be fair, they aren’t even _outputs_, they already exist and don’t get changed by the command; they would make more sense in the command’s `DEPENDS`, but then the command would never be ran.

## Edit 1

I wonder if you meant to use the expected final documentation files in `DEPENDS` and `OUTPUT`, and the “watched files” in the custom command’s `DEPENDS`.  
Like some index.html. I can’t do that. I’d like to be unaware of how the built documentation files are laid off. I’d just need to know the parent directory to install them.

## Edit 2

The `sphinx_generate_html` custom target generated by the [`FindSphinx.cmake`](https://github.com/InsightSoftwareConsortium/ITKExamples/blob/master/CMake/FindSphinx.cmake) I’m currently using has the `ALL` option…  
So I think that any attempt to avoid unnecessary documentation builds would be pointless. It was the only find module that defined a target, like the official Doxygen one.  
The [official FindDoxygen.cmake](https://gitlab.kitware.com/cmake/cmake/-/blob/master/Modules/FindDoxygen.cmake#L1124) seems to have some logic to decide the `ALL` option, but I’m not experienced enough to tell what it does.

---

<div class="post-metadata">

### Author: ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)
#### Post date: [June 3, 2020, 2:44pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/35 "2020-06-03T14:44:50Z")

</div>

> [@hex](#):
>
> A very comprehensive explanation on the difference between using export directly vs installing an export is given in the book “Professional CMake”.

I searched up the title out of desperation, and first I was a bit horrified by the amount of editions made in a such short period of time, but then I read that’s not a “standard book”, you’re able to access updated editions for free once you’ve paid.  
That’s probably why it’s so expensive (it costs more than “The C++ Programming Language”, cmon).  
I personally don’t think the documentation was particularly bad as it’s depicted on reddit, I’ve seen worse. It’s just terribly unhelpful at telling when to use the tools. To learn that you: a) spend a terrible month b) give up and write hideous code that works c) pay to get “Professional CMake”, choose one. I’ll find myself to have ran through all three of them soon

It happened to me a bunch of time to get thrown in some new language or tool, and being said “here, make it work”, but with CMake, trying to get a bit more than that revealed to be a nightmare.

I’m extremely grateful to everyone of you who kept answering my questions, I’ve learned so much while the thread got longer and longer, and I think continuing would be abuse of the forum, so I’ll stop here. I’ll continue with the book, off and on.  
thank you!

oof I can’t change the title to “(closed)”

---

<div class="post-metadata">

### Author: ![robert.maynard](https://discourse.cmake.org/user_avatar/discourse.cmake.org/robert.maynard/32/4_2.png) [@robert.maynard](https://discourse.cmake.org/u/robert.maynard)
#### Post date: [June 8, 2020, 2:10pm UTC](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768/36 "2020-06-08T14:10:42Z")

</div>

> [@Artemis](#):
>
> oof I can’t change the title to “(closed)”

I changed it for you.

[Previous page](https://discourse.cmake.org/t/cmake-project-review-and-suggestions-closed/768.md?page=1)
