3

We're using Jenkins 2.60.2 and CMake 3.9.1 to automate our build system. This all works well for multiple versions of build tools, architectures and debug/release targets (if ALL configurations have been built and installed, so both Debug AND Release).

A Debug-only configuration that uses find_package() typically ignores the CMAKE_BUILD_TYPE at discovery. Internally the scripts search for file and libraries and store the locations in variables. At the end of the script, the variables are scanned for _NOTFOUND strings, which is the result of a file or library not found in all the reference paths/hints. So essentially a find_package() will fail if the Release lib can not be found, and mark the whole package as not installed properly, even though the build is only strictly interested in the Debug target.

Typically the XXXConfig.cmake files use a call to find_package_handle_standard_args(.. PATH_TO_LIB) that scans for _NOTFOUND strings in the path variables to the libraries. These variables typically get set to _NOTFOUND by earlier calls to find_library(PATH_TO_LIB libname ..). For more information I refer to the CMake docs.

The user can indeed tag debug libraries with 'debug' and release libs with 'optimized', but this does not seem to help during the lib discovery and is only used during linking.

Anyone knows how to handle this properly?

Kind regards

StarShine
  • 1,632
  • 23
  • 40

1 Answers1

3

This is one of the unfortunate shortcomings of the classic use of find_package.

Note that find_package also allows a different mode of operation, based on config file packages, which is well-suited to address this particular problem, but will require some changes to your build system. You will need config scripts for all your libraries (CMake can generate them for you if the libraries are themselves also built by CMake; if not, this can be a bit of a hassle), and depending targets will refer to those libraries via imported targets instead of variables (which usually makes things way easier for those depending targets). I would strongly recommend you adopt this as the long-term solution.

If for some reason you cannot do this, you will have to modify your find scripts. A common technique is to search for debug and release binaries separately, but then combine the find libraries from those calls into a single variable (together with the debug and optimized specifiers) and then have that variable as an argument to find_package_handle_standard_args. That way, as long as one of the two is found, your find script will be happy, although you might not be able to build all possible configurations in the end. Alternatively, you can also skip the call to find_package_handle_standard_args altogether and manually implement your own logic for detecting whether the library was found. As you can see from the manpage for that function, it does mostly boilerplate stuff and can be easily replaced by a more flexible, handwritten implementation if necessary.

ComicSansMS
  • 43,180
  • 11
  • 123
  • 140
  • I dislike the second approach because it requires Config files to use configuration-specific variables for each and every dependency.. the possible explosion of that is rather unattractive. We have attempted the first solution but so far we failed to get the target approach working correctly due to missing lib/dll issues on windows. – StarShine Aug 28 '17 at 15:06
  • @StarShine I fully agree, the second approach is very cumbersome and I would not recommend it. But the unfortunate truth is, *someone* has to manage all those possible states. In the first approach, you can offload the majority of that to CMake but as long as you use hand written find scripts, you are more or less stuck with doing everything by hand. – ComicSansMS Aug 28 '17 at 15:17
  • Thanks to your suggestion I've given the build-by-target approach another and so far it seems to work (on Windows). We already have the config scripts for each lib setup anyway. I was just wondering ( to avoid duplicate script code ) if the 'fake' targets for imported libraries can go in custom find_package scripts? right now I have them in the cmake project configurations after invocation. – StarShine Aug 29 '17 at 21:58
  • Sure, a find script can expose its result through imported targets without problems. For example, the [`FindBoost` script](https://github.com/Kitware/CMake/blob/master/Modules/FindBoost.cmake) that ships with CMake learned to do this recently. – ComicSansMS Aug 30 '17 at 07:28
  • Exactly, thanks! You mentioned to drop hand-written find_package scripts, but I wonder how that works for people. From experience the scripts that CMake provides are often simple (versioning, debug/release, platforms..), inconsistent and somewhat naive, especially w.r.t cross-platform development. I find no better option than to support each target system by rewriting the default scripts, then handing everything over into mockup targets for import that links to relevant sub-modules. Can I assume this type of setup is common? – StarShine Aug 30 '17 at 11:42
  • @StarShine Careful, I said to replace find scripts by *config package scripts* generated by CMake. You will still need handwritten *find module scripts* for the cases where config package scripts are not applicable, and this is still a valid approach. It's not that find scripts have been deprecated, it is simply that for one (very popular) use case for find scripts, we now have a more powerful and convenient alternative available. If that alternative does not apply to your problem, there is nothing wrong in sticking with find scripts. – ComicSansMS Aug 30 '17 at 11:47
  • Ah yes of course thanks for clearing this up. We are already using some dozen config package scripts for our own modules and that indeed works wonderfully well. Hopefully at some point in the future system API's can be provided in this way too. – StarShine Aug 30 '17 at 20:40