Where are CMAKE_HOST_APPLE / CMAKE_HOST_UNIX / CMAKE_HOST_WIN32 set? - build

I've started digging in under the hood so that I can better understand the inner workings of CMake. I've been going through the files in the Modules directory in order to understand how/why/when things happen when running CMake.
I've so far been unable to determine how/where the CMAKE_HOST_APPLE/CMAKE_HOST_UNIX/CMAKE_HOST_WIN32 variables are set.
Can anyone enlighten me?
On a related note, I've been going through the Modules files in a haphazard manner since I don't know the order in which they are initiated/processed.
Is there anywhere that describes this flow or at the very least indicates a starting point so that I can figure out the rest from there?

Those variables are set in CMake's code surrounded by platform dependent #ifdef checks, so you can say they are set during compile time of CMake itself.
I also had some difficulties locating the source file in question, because the code to add those default variable definitions has just recently moved from cmMakefile::AddDefaultDefinitions() to cmState::Snapshot::SetDefaultDefinitions() (see this commit).
Here is an example from cmState.cxx:
#if defined(__APPLE__)
this->SetDefinition("APPLE", "1");
this->SetDefinition("CMAKE_HOST_APPLE", "1");
#endif
For more information on how CMake does work see:
CMake: In which Order are Files parsed (Cache, Toolchain, …)?
How to frame the concept behind CMake?
About CMake
The Architecture of Open Source Applications: CMake

Related

How can I link a library that contains conditional types/variables definition based on global variables defined through CMake?

Introduction
I am trying to use Toulbar2 as a C++ library in my CMake project, however I am having much trouble linking it to my main executable.
I found many similar questions on this topic, both here and on other similar website, but none of them helped me with my specific issue. I tried literally everything and I did not menage to make it work, I was hoping that some of you may help me with that.
I am running Ubuntu 18.04, CMake version 3.23 and in my project I am using the standard C++11. I am a proficient programmer, but I am just an beginner/intermediate user of both C++ and CMake.
What I've already tried to do
I cannot list all my attempts, so I will only mention those I think are my best ones, to give you an idea of what I may be doing wrong.
1) In my first attempt, I tried to use the same approach I used for any non-standard library I imported, i.e. using find_package() in CMakeLists.txt to then link the found LIBRARIES and include the found INCLUDE_DIRS. However, I soon realised that Toulbar2 provides neither a Find<package>.cmake or <name>Config.cmake file. So, this approach could not work.
2) My second attempt is the one that in my opinion brought me the closest to the solution I hoped for. You can easily compile Toulbar2 as a dynamic library using the command: cmake -DLIBTB2=ON .. in an hypothetical build directory you previously created. After compiling with make you have your .so file in build/lib/Linux. After installation, you can make CMake find this library by itself using the command find_library. So, my CMakeLists.txt ended up looking like this:
[...]
find_library(TB2_LIBRARIES tb2)
if(TB2_LIBRARIES)
set(all_depends ${all_depends} ${TB2_LIBRARIES})
else(TB2_LIBRARIES)
add_compile_definitions("-DNO_TB2")
message("Compiling without Toulbar2, if you want to use it, please install it first")
endif(TB2_LIBRARIES)
[...]
target_link_libraries(main ${all_depends})
[...]
This code works to some extent, meaning that CMake correctly finds the library and runs the linking command, however if I try to #include <toulbar2lib.hpp> the header is not found. So I figured out I should have told CMake where to find that header, so I ended up adding a
include_directories(/path/to/header/file's/directory)
However, I still have another problem. The header is found, but a lot of names used in the header are not found at compilation time. The reason is that in Toulbar2 some variables/types are defined conditionally by using preprocessing directives like #ifdef or #ifndef, and in turn the global variables used in these conditions are defined through CMake at compilation time. If you are interested in an example, I can mention the Cost type that is used in the mentioned header file. I see that there's a piece missing in the puzzle here, but I cannot figure out which one. Since I pre-compiled the library those definitions should exist when I include the header file, because I am correctly linking the correspondent library that contains those definitions.
3) My third attempt is less elegant than the the other two I mentioned, but I was desperately trying to find a solution. So, I copied the whole toulbar2 cloned folder inside my project and I tried to add it as a subdirectory, meaning that my main CMakeLists.txt contains the line:
add_subdirectory(toulbar2)
It provides a CMakeLists.txt too, there should be no problem in doing it. Then I include the src directory of toulbar2, that contains the header file I need, and I should be okay. Right? Wrong. I got the same problem that I had before with (2), i.e. some variables/types conditionally defined were not actually defined when I tried to compile my project, even though the subproject toulbar2 was correctly (no errors) compiled.
I just wanted to mention that any answer is welcome, however if you could help me figure out an elegant solution (see 1 or 2) for this problem it would be way better, as this code is intended to be published soon or later. Thank you in advance for your help.
Solution 2) looks fine. You just need to add the following compilation flags -DNDEBUG -DBOOST -DLONGDOUBLE_PROB -DLONGLONG_COST when compiling your project with toulbar2lib.hpp. See github/toulbar2 README.md how to compile without cmake for those flags (except WCSPFORMATONLY that should not by used in this context).

CMake doesn't link the actual object to the resulting dll [duplicate]

How do I define a preprocessor variable through CMake?
The equivalent code would be #define foo.
For a long time, CMake had the add_definitions command for this purpose. However, recently the command has been superseded by a more fine grained approach (separate commands for compile definitions, include directories, and compiler options).
An example using the new add_compile_definitions:
add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION})
add_compile_definitions(WITH_OPENCV2)
Or:
add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION} WITH_OPENCV2)
The good part about this is that it circumvents the shabby trickery CMake has in place for add_definitions. CMake is such a shabby system, but they are finally finding some sanity.
Find more explanation on which commands to use for compiler flags here: https://cmake.org/cmake/help/latest/command/add_definitions.html
Likewise, you can do this per-target as explained in Jim Hunziker's answer.
To do this for a specific target, you can do the following:
target_compile_definitions(my_target PRIVATE FOO=1 BAR=1)
You should do this if you have more than one target that you're building and you don't want them all to use the same flags. Also see the official documentation on target_compile_definitions.
The other solutions proposed on this page are useful for some versions of Cmake > 3.3.2. Here the solution for the version I am using (i.e., 3.3.2). Check the version of your Cmake by using $ cmake --version and pick the solution that fits your needs. The cmake documentation can be found on the official page.
With CMake version 3.3.2, in order to create
#define foo
I needed to use:
add_definitions(-Dfoo) # <--------HERE THE NEW CMAKE LINE inside CMakeLists.txt
add_executable( ....)
target_link_libraries(....)
and, in order to have a preprocessor macro definition like this other one:
#define foo=5
the line is so modified:
add_definitions(-Dfoo=5) # <--------HERE THE NEW CMAKE LINE inside CMakeLists.txt
add_executable( ....)
target_link_libraries(....)
PLEASE NOTE (as #squareskittles suggests in one of the comment): "if you are using CMake 3.3.2, you have to use add_definitions() or target_compile_definitions(). The more modern command, add_compile_definitions(), was not added until CMake 3.12."
1.) target_compile_definitions
If you are using CMake 3.X your first choice for adding a preprocessor macro should be target_compile_definitions.
The reason you should prefer this approach over any other approach is because it granularity is target based. IE the macro will only be added to your exe/library.
Here is a common example:
if (WIN32)
target_compile_definitions(my_lib PRIVATE
# Prevents Windows.h from adding unnecessary includes
WIN32_LEAN_AND_MEAN
# Prevents Windows.h from defining min/max as macros
NOMINMAX
)
endif()
2.) add_compile_definitions
New in version 3.12.
Find more explanation on which commands to use for compiler flags here: https://cmake.org/cmake/help/latest/command/add_definitions.html
add_compile_definitions applies macros to any targets that are defined after the call.
Here is the same logic as above with add_compile_definitions.
add_compile_definitions(WIN32_LEAN_AND_MEAN NOMINMAX)
add_library(my_lib)
If you use this approach be careful if you are the top level project.
Otherwise if users consume your library using add_subdirectory they may have issues.
3.) The other less recommended ways
These approaches really aren't recommended anymore. Due to not being modular, not scaling well, not supporting generator expressions, etc.
add_definitions
CMAKE_LANG_FLAGS
Why is target_compile_definitions better/preferred?
It's much more clear to readers of your CMake code how it works.
Allows usage of PRIVATE/PUBLIC/INTERFACE if needed. Which can make life easier for consumers of your library.
It's much more modular.
Applying pre-processor flags (Or any compiler flag) globally can create hidden dependencies in your build.
Essentially think of add_compile_definitions as globals in C/C++. Sometimes you need them, but be careful.
i'd like to recommend use target_*** operations instead of add_*** operations when your solution include many projects.
here is an example where you can pass values from CMAKE to C++ code. Say, you want to pass:
flag, here: BOOST ("true" or "false")
software version string (e.g.: "1.0.0")
I recommend to pass them as strings.
So, when you build software with CMAKE, you can pass parameters like for example if it was built using boost library, software version pulled from CMAKE variable (so that you change that number only in one place)
See below.
In CMakeLists.txt:
add_compile_definitions(
BOOST="${BOOST}"
Software_VERSION="${PROJECT_VERSION}"
)
In your .cpp code:
std::cout << "Software version is: " << Software_VERSION << " BOOST: " << BOOST << "\n";
Hope this helps. Regards.

C++: Where to place files using #include <> with angle brackets

Context:
I am trying to run the code for a thin-plate spline provided by Jarno Elonen at http://elonen.iki.fi/code/tpsdemo/. It requires the installation of OpenGL + GLUT and the Boost uBlas library. I have downloaded the code, but I have been unable to run it because the compiler can't locate the GLUT and Boost files.
I'm hoping that someone can get the code on the website to run (and not just address the immediate trouble I'm facing), and tell me the exact steps to follow to get it to run. (I don't mind if you dumb it down completely, I'm a beginner :) )
What I have done so far:
Downloaded and extracted tpsdemo-1.2.tar.gz from the website above
Downloaded FreeGLUT (because various online forums told me I should be doing this as GLUT itself is outdated...): Freeglut 3.0.0 from freeglut.sourceforge.net/index.php#download.
Downloaded Boost: boost_1_61_0.zip from www.boost.org/users/history/version_1_61_0.html.
I don't know what to do from here... where should I put these files so that the code from tpsdemo-1.2 can access them? I have tried putting it in the same directory, but this seems to require using #include "filename" with quotation marks instead of the #include <filename> with angle brackets which is in the provided code. If I do alter it like this, then it seems like I will have to change all include statements in GLUT and Boost (which currently use angle brackets) which is not a small task. (I don't really want to be modifying too much code...) What's the correct way to do this? I have tried using the -Idir tag while compiling but this runs into other problems, although I don't know if this problem is to do with GLUT/Boost (which is why I'd like to see if anyone else can get the code to run!)
wedge brackets in a#include are for denoting files that exist on a system or framework level. As such you never get them there by moving them into the "right" place, but instead you specify which directories are to be considered "system" or "framework" level. The exact method in the end is depending on the compiler used, but all major compilers out there understand the -I${PATH_TO_INCLUDE_DIRECTORY command line option notation. -I… may be specified multiple times to specify multiple directories.
It is a good style to use wedge bracketed includes exclusively for headers that are 3rd party to a project and/or for headers that form the framework of a project. For headers that belong to modules of a project itself quotation marks should be used.

Bit definition error - IAR Workbench

I am a beginner with embedded programming and am using the IAR workbench for a project of mine using STM32F4Discovery. I am trying to compile an existing code and have a few errors at a few places regarding the bit definitions like the following:
Error[Pe020]: identifier "GPIO_PIN_SET" is undefined
Now, the GPIO_PIN_SET is defined in the file stm32f4xx_gpio_hal.h and is already included in my project. In order to resolve this issue when I looked up online, I have found this solution. However, I don't have the System tab in the General Options in my IAR Workbench. I have a full version of IAR Workbench and am not sure why the System tab is missing.
I also tried defining
#define ENABLE_BIT_DEFINITIONS
as stated in this link in my main.c file but to no avail.
Trying to set
#define STM32F4XX
#define USE_STDPERIPH_DRIVER
in the main.c file or defining the symbols STM32F4XX, USE_STDPERIPH_DRIVER in the Preprocessor tab in General Options as mentioned here also didn't help.
The solution could be very simple that I am probably overlooking but am not able to figure out what could I be missing. Any help would be appreciated
Including a header file in a "project" is not enough, you should actually include it (directly or indirectly) in the source file where the declarations are to be used. It would be that simple in any halfway sane development kit, but we are stuck with ST, and they force us doing it their way.
Include the "master" header in your main.c
#include "stm32f429i_discovery.h"
this would in turn include stm32f4xx_hal.h, which includes stm32f4xx_hal_conf.h, which included stm32f4xx_hal_gpio.h if the right #defines were there.
You might not have stm32f4xx_hal_conf.h
If that's the case, then copy Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_conf_template.h into your project, rename it to stm32f4xx_hal_conf.h. Otherwise just make sure that #define HAL_GPIO_MODULE_ENABLED is not commented out.
Set the right #defines
New versions of STM32CubeF4 have been released since the tutorial you've linked was written, and a few things have apparently changed. As of version 1.6.0, define STM32F429xx in Preprocessor Options, and forget the ones above. Yes, I've noticed that there is a version 1.7.0 now, let's hope that compatibility lasts this time.

Including libsimdpp in a CMake project

I decided to use libsimdpp for vectorization of my C++ code. Problem is, there is next to no documentation on how to get started.
Í assumed inclusion would be simple given that it's also CMake based like the project I'm doing, so I just tried to copy over the directory and set the include path. Well, turns out this is not enough: You need to define the appropriate flags to specify which SIMD flavor you want to compile for. libsimdpp includes a CMake macro just for that and it works wonders. I'm not sure however how to get going from here and it feels like I'm working against CMake rather than with it by copying things around and deleting stuff.
Would anyone with a firm understanding of CMake set out to explain what to do in a step-by-step fashion? Thanks!
You should check out the simdpp/test/CMakeLists.txt file where the tests of libsimdpp are compiled. The relevant parts are these:
foreach(SRC ${TEST1_ARCH_SOURCES})
simdpp_multiarch(TEST1_ARCH_GEN_SOURCES ${SRC} ${COMPILABLE_ARCHS})
endforeach()
add_executable(test1 EXCLUDE_FROM_ALL
${TEST1_SOURCES}
${TEST1_ARCH_GEN_SOURCES}
)
Basically, TEST1_ARCH_SOURCES contains the code that uses libsimdpp. simdpp_multiarch copies the sources around and sets appropriate compile flags for them, so that implementations for e.g. SSE2 and AVX2 can be linked into the same executable. Then these generated sources (TEST1_ARCH_GEN_SOURCES) are added into the executable.