CMake and MinGW-w64 include paths - c++

I have a C++ project that needs to be built with CMake and MinGW-W64.
Some libraries (such as zlib, libpng) are in: C:\Dev\mingw64-5.3.0\x86_64-w64-mingw32\
So I use : -DCMAKE_PREFIX_PATH="C:\Dev\mingw64-5.3.0\x86_64-w64-mingw32"
But, I get a compilation error because the following header is outdated and miss important symbols:
C:\Dev\mingw64-5.3.0\x86_64-w64-mingw32\include\float.h
If I add a compiler flag to search into the proper include directory for float.h:
-DCMAKE_CXX_FLAGS="-isystem C:/Dev/mingw64-5.3.0/lib/gcc/x86_64-w64-mingw32/5.3.0/include"
Then, this does not work, since CMake will add this folder after its generated includes_CXX.rsp
How can I handle this issue? Is there a way to enforce header search path priority?

You could also add the include location(s) to environment variable C_INCLUDE_PATH and CPLUS_INCLUDE_PATH.
To locate the libraries you can do the same for the lib with the LIBRARY_PATH environment variable.
For DLL and EXE files you may even need to add the bin path to PATH.

Related

Custom library directory for cmake

For my project, I am building specific versions of the dependency libraries in a separate folder, say, /home/ubuntu/libs. I will use real libraries as an example, however, the question is pretty generic.
I was able to build the freetype library and make installed the headers into /home/ubuntu/libs/include, the built library into /home/ubuntu/libs/lib and also added the freetype-config.cmake to /home/ubuntu/libs/lib/cmake.
Now, I am trying to build the freetype-gl library that depends on freetype and has a line
find_package(freetype REQUIRED) in its CMakeLists.txt.
Typically, when I install the freetype library to a common path like /usr/local/lib or /usr/lib, cmake picks up the *-config.cmake files from the corresponding ./cmake directory. However, when I call it with
cmake -DCMAKE_TOOLCHAIN_FILE=/my/custom/toolchain -DCMAKE_LIBRARY_PATH=/home/ubuntu/libs/lib -DCMAKE_INCLUDE_PATH=/home/ubuntu/libs/include /path/to/freetype-gl
it fails with the following error
CMake Error at CMakeLists.txt:102 (find_package):
By not providing "Findfreetype.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "freetype",
but CMake did not find one.
Could not find a package configuration file provided by "freetype" with any
of the following names:
freetypeConfig.cmake
freetype-config.cmake
Add the installation prefix of "freetype" to CMAKE_PREFIX_PATH or set
"freetype_DIR" to a directory containing one of the above files. If
"freetype" provides a separate development package or SDK, be sure it has
been installed.
What am I doing wrong? How to show the place of "freetype-config.cmake" to cmake.
as you state in your second paragraph:
I was able to build the freetype library and make installed the headers into /home/ubuntu/libs/include, the built library into /home/ubuntu/libs/lib and also added the freetype-config.cmake to /home/ubuntu/libs/lib/cmake.
find_package() in CMake works in a way that it checks the standard system paths on default. If you are using CMake version 3.17 you can (instead of reading the documentation) view these paths simply by adding this line to your CMakeLists.txt
SET(CMAKE_FIND_DEBUG_MODE TRUE)
In your case what you need to do is point CMake in the right direction of the cmake file you are looking for. In your case that would be the /home/ubuntu/libs/lib/cmake. So somewhere in the top of your CMakeLists.txt (before you call find_package()) add this line:
LIST(APPEND CMAKE_MODULE_PATH "/home/ubuntu/libs/lib/cmake")
Provided that this bash command:
ls /home/ubuntu/libs/lib/cmake | grep "*.cmake"
Returns an occurance of freetypeConfig.cmake (you get the drill :) )
You can read about CMAKE_MODULE_PATH variable here: https://cmake.org/cmake/help/latest/variable/CMAKE_MODULE_PATH.html
In short your CMake doesn't find the config file because it is not in the standard path where it expects to find it.
EDIT: You can ofcourse do the same via these variables as the error suggests - CMAKE_PREFIX_PATH or freetype_DIR
Presumably you also don't want the libraries you build to find their dependencies installed on our system, if any.
I've spent some time investigating how to isolate CMake builds, and my best recipe is below.
First, the terminology:
An installation "prefix" of a library is a directory where the binaries and headers are installed (normally in include and lib subdirectories). I preder distinct prefixes for each library.
A "dependency" of a library is any of other library it needs when compiling.
CMake path separator - the character used to separate path lists for CMake. It's : character on Windows and ; on Linux (when cross-compiling, the host system matters, not the target).
Yes, it's the opposite of what the documentation claims.
By Windows I mean MSYS2. If you want to build outside of it, check that : is still the right separator.
Environment variables for CMake:
PKG_CONFIG_PATH to empty string
PKG_CONFIG_LIBDIR to a :-separated list, for each dependency add <prefix>/lib/pkgconfig and <prefix>/share/pkgconfig.
(I didn't need to do it for any library I used, so this is theoretical. But in any case don't leave this variable unset, at least use an empty string. Otherwise some undesired dependencies from your system might leak in.)
CMake flags:
-DCMAKE_INSTALL_PREFIX=... - the installation prefix for this library.
-DCMAKE_PREFIX_PATH=... - a path list: the installation prefix, followed by the prefixes of all dependencies. Use the CMake path separator, as described above. All paths here must be absolute.
-DCMAKE_FIND_USE_CMAKE_SYSTEM_PATH=OFF
This prevents CMake from finding some system-wide dependencies. If I remember correctly, not doing this makes CMake look for dependencies in directories listed in PATH and their parent directories, which is annoyting.
This has an undesired effect of disabling some ..._SYSTEM_... CMake variables, so we can't use those, even though some of them would be more appropriate.
-DCMAKE_STAGING_PREFIX=/. On Windows hosts replace / with the current drive name, e.g. C:.
This is only useful when cross-compiling, to disable the effects of CMAKE_FIND_ROOT_PATH in the toolchain file, which otherwise limits dependency search to that path.
This also messes up the installation path that would otherwise be taken from CMAKE_INSTALL_PREFIX, the fix is explained below.
Only on Windows hosts:
-DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF - otherwise CMake tends to look for dependencies in the PATH and parent directories, which is annoying. This is hardcoded to only happen on Windows hosts, which is nonsense and was reported here.
We don't want to set this unconditionally, because it has a side effect of requiring all your toolchain executables to be in the same directory, which is annoying in general, but IMO tolerable on Windows.
It also prevents CMake from searching for executables in PATH, so we also need...
-DCMAKE_PROGRAM_PATH= - set this to the contents of PATH, with the original separator replaced with the CMake path separator. At least on MSYS2 the separators are the same, so no modifications are needed.
-DCMAKE_MAKE_PROGRAM=ninja -GNinja - here CMAKE_MAKE_PROGRAM is strictly necessary on Windows hosts because of CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF, and doesn't hurt on other platforms. -G... is to make sure CMake doesn't pick a different generator that doesn't match CMAKE_MAKE_PROGRAM. You can use any other generator+program if you wish.
Then build with cmake --build <build_dir> -j<num_threads> as usual.
Install with cmake --install <build_dir> --prefix <prefix>. We need to explicitly set prefix because of CMAKE_STAGING_PREFIX=/.

Compiling QT OPCUA on Windows

I have a problem when I try to compile Qt OPCUA on windows with open62541.
I am following this tutorial (Building On Windows - Mingw32)
I cannot seem to specify the path to the header open62541.h and the lib open62541.a even if I did
set QTOPCUA_OPEN62541_INCLUDE_PATH=c:\path\to\open62541\build
set QTOPCUA_OPEN62541_LIB_PATH=c:\path\to\open62541\build\bin
Note that open62541 is compiled and that I do have the files open62541.h and libopen62541.a (in version 0.3) where they should be.
The error I get is a linker problem : cannot find -lopen62541
I added manually the open62541.h to the project files since it was not working either.
What should I do to specify correctly the path to open62541 please ? Is there an up-to-date documentation ?
You need to add the path where libopen62541.a is to the library path directory.
If you are using QMake, you need to specify add it to the LIBS variable prepending the path with a -L as follows:
LIBS += -L$${PATH_WHERE_LIB_FILE_IS}
Take a look on how is done in the QUaServer project.
If you are using CMake, then take a look at this answer on how to add to the library path directory.
What you are doing with those commands is telling the linker where to find the missing libraries.

How to change default executable, library and include path in Cmake windows

Am trying to change default storage of the library, executable and include files to a specified directory in Cmake.
For e.g.: When I run Cmake, it will get build in a particular directory (where the source files are kept) and also generates the executables, libraries and include files in the same source directory. I want to define the output path for executables, libraries and include files in below structure.
X:\Builddirectory\lib\Debug\.... library files.
X:\Builddirectory\lib\Release\.... library files.
X:\Builddirectory\include\.... all the include files.
X:\Builddirectory\bin\.... executable files.
In order to perform the above, following CMake variables needs to be set.
But I am not aware how to edit these variables:
LIBRARY_OUTPUT_PATH
EXECUTABLE_OUTPUT_PATH
PROJECT_BINARY_DIR
may be some other variables as well.
Thanks for suggestions and help.
Once you open the CMAKE gui, Check for the above mentioned cmake variables, if they are not defined or defined with default path Consider performing the below mentioned.
1. If defined with default path then change it to the desired PATH
2. If the variable is not defined/assigned or could you not find in the CMAKE list then consider adding the variable by using "ADD Entry" option in the Gui.

Add only specific subdirectory of an include path to includes

I have a project which is built using cmake.
This project is uses avr-gcc to compile the binaries and I use boost mpl for some parts of it.
As avr-gcc does not have /usr/include as a default include path but boost is installed there, I need to add it as an include path such that boost is found.
Unfortunately, adding -I/usr/include to the command line pulls in all other files and directories in /usr/include which seems to introduce collisions with the avr includes and thereby compiler errors.
My initial solution involved a softlink to /usr/include/boost in one of my user defined include directories to resolve the
#include <boost/mpl/*>
However, I thought this to be not very platform independent and decided for cmake to add the include path for boost. This again led to "-I/usr/include" being present on the compiler command.
How do I solve this in a platform agnostic manner?
A solution would be to let cmake create the link for me to get the right include directory.
However, I consider the whole symbolic link solution ugly.
Is there something better that I can do?
For example: Is there some option that adds an include path under an alias like:
-I/usr/include/boost:boost
Which would add only the boost subfolder under the name boost to be includable by the #include <boost/...> directive?
I see at least two options for you:
Where does avr-gcc include files from by default? Let's say it is /opt/avr-gcc/include for concreteness. Then what may work for you is -I/opt/avr-gcc/include -I/usr/include.
Another option is to install Boost in a different directory and use that instead of the Boost in /usr/include. For example, you might create /opt/boost and then use -I/opt/boost (or a sub-directory under that) on the command line.

Add extra include/lib paths to MinGW

I would like to add some extra include/lib directories besides the default ones for MinGW to search upon compilation. The reason for this is because the hard drive I currently have MinGW installed into is nearly full and so I had to install Qt into my second one instead. Thus, how can I have MinGW include the Qt files by default?
You can set environment variables CPLUS_INCLUDE_PATH for include directories and LIBRARY_PATH for library directories. More information can be found in Environment Variables Affecting GCC
Use -Idirective for extra includes and -Ldirective for extra library paths such as:
g++ [...] -I C:\qt\include -L C:\qt\lib
You can use multiple -Iand -Loptions.