How is cmake finding my llvm cmake configuration? - cmake

I am wondering how is cmake finding my llvm cmake configuration if I haven't given it any variable telling it where to find it.
I am an LLVM newcomer. I am building a Hello World LLVM pass. I am on Ubuntu 16.04. My version of LLVM is 8.0.0. My version of CMake is 3.5.1.
This is my /CMakeLists.txt file:
cmake_minimum_required(VERSION 3.1)
project(FunctionDebugger)
find_package(LLVM REQUIRED CONFIG)
include_directories(${LLVM_INCLUDE_DIRS})
add_subdirectory(FunctionDebugger)
set(CMAKE_VERBOSE_MAKEFILE on)
This is the FunctionDebugger/CMakeLists.txt file:
add_library(LLVMFunctionDebugger MODULE
FunctionDebugger.cpp
)
set_target_properties(LLVMFunctionDebugger PROPERTIES
COMPILE_FLAGS "-fno-rtti -std=c++11"
)
I configure and compile like this:
mkdir build && cd build
cmake ..
make
It correctly compiles and links a shared library called libLLVMFunctionDebugger.so. What I don't understand is how cmake could find the package requested in:
# <project-root>/CMakeLists.txt
find_package(LLVM REQUIRED CONFIG)
I am not giving it any path nor I have anything defined in the environment but the path to the LLVM binaries.
I read the CMake documentation, but it says that the find_package looks in folders under CMAKE_PREFIX_PATH. I print that variable with message(STATUS ${CMAKE_PREFIX_PATH}) and the output is empty.

Your set-up looks correct and clearly CMake is finding LLVMConfig.cmake script (i.e. the script that find_package consumes to propagate the necessary CMake variables with LLVM 8 set-up).
On the Ubuntu 16.04 machine that I have access to, LLVMConfig.cmake is located in /usr/lib/llvm-8/lib/cmake/llvm/LLVMConfig.cmake, but there's also a symlink in /usr/lib/llvm-8/cmake/. So the natural questions is: does CMake know that it should look there? The answer is yes. In CMake docs you can see that one of the search paths is:
<prefix>/(lib/<arch>|lib|share)/<name>*/(cmake|CMake)/ (U)
You can verify that usr is on the list of prefixes by printing CMAKE_SYSTEM_PREFIX_PATH. On my machine that's set-up to:
/usr/local;/usr;/;/usr;/usr/local
Finally, you can print LLVM_DIR in your CMake script to check which version/installation of LLVM was picked by find_package. The variable will be empty on the first execution of CMake, but then find_package finds LLVM-8, the variable is set and saved in CMakeCache.txt.
Hope this helps.
EDIT
This answer was tested on Ubuntu 16.04 on which LLVM 8 was installed in the default, system-wide location through apt-get. If you install LLVM 8 elsewhere, then there are various ways of pointing CMake to the right location, see the docs for find_package. Editing the PATH variable is one of them:
Search the standard system environment variables. This can be skipped if NO_SYSTEM_ENVIRONMENT_PATH is passed. Path entries ending in /bin or /sbin are automatically converted to their parent directories:
PATH

Since cmake 3.17, you can use cmake --debug-find <cmake-options> to ask cmake to output a bunch of debugging information on find_* functions. On my machine, it outputs
Standard system environment variables [CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH].
/home/jiaqi/Documents/LLVM/llvm-project/build
/home/jiaqi/.local
/home/jiaqi/.yarn
/home/jiaqi/anaconda3
/home/jiaqi/anaconda3/condabin
/usr/local
/usr
/
/usr/games
/usr/local/games
/snap
... outputs omitted...
find_package considered the following locations for LLVM's Config module:
/home/jiaqi/Documents/LLVM/Test/build/CMakeFiles/pkgRedirects/LLVMConfig.cmake
/home/jiaqi/Documents/LLVM/Test/build/CMakeFiles/pkgRedirects/llvm-config.cmake
/home/jiaqi/Documents/LLVM/llvm-project/build/LLVMConfig.cmake
/home/jiaqi/Documents/LLVM/llvm-project/build/llvm-config.cmake
/home/jiaqi/Documents/LLVM/llvm-project/build/cmake/LLVMConfig.cmake
/home/jiaqi/Documents/LLVM/llvm-project/build/cmake/llvm-config.cmake
/home/jiaqi/Documents/LLVM/llvm-project/build/lib/cmake/llvm/LLVMConfig.cmake
The file was found at
/home/jiaqi/Documents/LLVM/llvm-project/build/lib/cmake/llvm/LLVMConfig.cmake
So, the cmake is using Config mode here and the file is located at /home/jiaqi/Documents/LLVM/llvm-project/build/lib/cmake/llvm/LLVMConfig.cmake
To figure out how cmake finds the LLVMConfig.cmake, take a look at https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure
For step 5, it says the cmake will search the environment variable $PAT, and note that
Path entries ending in /bin or /sbin are automatically converted to their parent directories.
Since I have put the path to llvm executables in $PATH:
$ echo $PATH
/home/jiaqi/Documents/LLVM/llvm-project/build/bin:/home/jiaqi/.local/bin:/home/jiaqi/.yarn/bin:/home/jiaqi/anaconda3/bin:/home/jiaqi/anaconda3/condabin:/home/jiaqi/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
The folder /home/jiaqi/Documents/LLVM/llvm-project/build will be used as prefix. According to https://cmake.org/cmake/help/latest/command/find_package.html#config-mode-search-procedure, the folder <prefix>/(lib/<arch>|lib*|share)/cmake/<name>*/ will be searched.

Related

Setting Cmake Library paths without Editing CmakeLists

Goal: To set Cmake Paths without having to edit the CMakeLists.txt file.
In Linux, using find_library() in Cmake is enough to find a library installed with apt.
In Windows, Cmake is unable to find it automatically.
Note: Please treat sqlite3 as any library.
What is the proper method to set the library paths which cmake searches for my library files without having to edit CMakeLists?
Note: I have samlib compiled to a static library file and placed in some directory away from the project itself.
I have tried the following on Linux and Windows.
cmake_minimum_required(VERSION 3.0.0)
project(SampleProj VERSION 0.1.0)
find_library(samlib NAMES samplelib)
add_executable(SampleProj src/main.cpp)
target_link_libraries(SampleProj ${samlib})```
Try to use CMAKE_LIBRARY_PATH
Semicolon-separated list of directories specifying a search path for the find_library() command. By default it is empty, it is intended to be set by the project. See also CMAKE_SYSTEM_LIBRARY_PATH and CMAKE_PREFIX_PATH.
src: https://cmake.org/cmake/help/latest/variable/CMAKE_LIBRARY_PATH.html
set CMAKE_GENERATOR=Visual Studio 15 2017 Win64
cmake -H. -Bbuild -G "%CMAKE_GENERATOR%" "-DCMAKE_PREFIX_PATH=path_to_samlib"

CMake error with GTKmm - No package 'gtkmm-3.0' found

This may be related to my previous question.
I copied the code from the "Simple Example" here.
I copied the cmake instructions from here.
The error I am getting is:
-- Checking for module 'gtkmm-3.0'
-- No package 'gtkmm-3.0' found
CMake Warning (dev) in CMakeLists.txt:
No cmake_minimum_required command is present. A line of code such as
cmake_minimum_required(VERSION 3.10)
should be added at the top of the file. The version specified may be lower
if you wish to support older CMake versions for this project. For more
information run "cmake --help-policy CMP0000".
This warning is for project developers. Use -Wno-dev to suppress it.
-- Configuring done
-- Generating done
-- Build files have been written to: /path-to-files/
This is my CMakeLists.txt
project(SimpleExample)
find_package(PkgConfig REQUIRED)
set(CMAKE_PREFIX_PATH "/usr/lib/x86_64-linux-gnu/pkgconfig;/usr/share/pkgconfig")
pkg_check_modules(GTKMM gtkmm-3.0)
link_directories(${GTKMM_LIBRARY_DIRS})
include_directories(${GTKMM_INCLUDE_DIRS})
add_executable(SimpleExample SimpleExample.cpp)
target_link_libraries(SimpleExample ${GTKMM_LIBRARIES})
There's a really dumb line in here set(CMAKE_PREFIX_PATH "/usr/lib/x86_64-linux-gnu/pkgconfig;/usr/share/pkgconfig") which I'm fairly sure isn't supposed to be there, however in my previous question I was struggeling to figure out why pkg-config wasn't finding the correct locations for the gtkmm-3.0.pc file.
So I did a search to try and figure out how to set the paths for pkg-config manually in a CMake file. That is what I came up with. However it does not work.
CMake variable CMAKE_PREFIX_PATH and environment variable PKG_CONFIG_PATH denote different paths:
CMAKE_PREFIX_PATH points to the installation prefix(es) of the one or more programs.
PKG_CONFIG_PATH points to location(s) of .pc files.
When CMake wants to call pkg-config via pkg_check_modules command, it translates content of CMAKE_PREFIX_PATH variable into PKG_CONFIG_PATH by appending sufficies to every path in CMAKE_PREFIX_PATH variable (see branch if(NOT "${_extra_paths}" STREQUAL "") in FindPkgConfig.cmake):
lib/pkgconfig
share/pkgconfig
lib32/pkgconfig or lib32/pkgconfig for some distros
some other system-specific sufficies
As you can see, you may obtain /usr/share/pkgconfig in PKG_CONFIG_PATH by using /usr in CMAKE_PREFIX_PATH.
But obtaining /usr/lib/x86_64-linux-gnu/pkgconfig in PKG_CONFIG_PATH is very questionable.
In any case, parameters described the host system itself are normally passed via environment or cmake arguments, not by the project's CMakeLists.txt. In given case command line
export PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig"
is much more simpler (and reliable) than setting CMAKE_PREFIX_PATH CMake variable.

Changed find_library behavior from CMake 2.8 to CMake 3.2

I have got the following problem while migrating from CMake 2.8.x to 3.2.x. Thereby, it seems that the internal behavior of find_library changed. Here is a minimal example which demonstrates my problem.
Consider that we are search for library called libopenblas.so which is located in /scratch/local_install/lib and /usr/lib/openblas-base. The LD_LIBRARY_PATH environment variable is set to /scratch/local_install/lib.
The CMakeLists.txt file is the following:
PROJECT(TEST)
cmake_minimum_required(VERSION 2.8)
SET(_libname "openblas")
SET(_libdir ENV LD_LIBRARY_PATH "/usr/lib/openblas-base")
find_library(OPENBLAS_LIBRARY
NAMES ${_libname}
HINTS ${_libdir}
PATHS ${_libdir}
)
MESSAGE("OPENBLAS: ${OPENBLAS_LIBRARY}")
If I execute this using CMake 2.8.7 or 2.8.12, I get
OPENBLAS: /scratch/koehlerm/local_install/lib/libopenblas.so
If I configure the code using CMake 3.2.1, I get
OPENBLAS: /usr/lib/openblas-base/libopenblas.so
which I only want to get if there is none libopenblas.so in the LD_LIBRARY_PATH. How can I restore the old behavior of CMake 2.8.x even if the code is configured with CMake 3.2.x?
Use NO_DEFAULT_PATH for find_library, then it will ignore the default location. See the documentation.
To get the bahvior you want, use find_library twice. First with NO_DEFAULT_PATH and after that without. If it is found the first time, the result is cached and the second call including the default path is skipped. If nothing is found first, it will be re-run and look at the default paths, too.

Compiling a CMake project against libraries in a non-standard location

I have two projects using CMake.
The first is a shared library. It compiles and installs fine. Currently, it is still necessary to build 'debug' releases of it. So presently it is installed under ~/localdebug. That folder looks like the root of a filesystem with a 'include' and 'lib' directory. The same concept as '/usr/local'.
The second is a program. It needs to compile and link against my library in ~/localdebug. The CMakeLists.txt file for it looks like this:
cmake_minimum_required(VERSION 2.6)
set(CMAKE_C_FLAGS "-std=gnu99")
#add_definitions(-pg)
find_library(SANDGROUSE_LIB NAMES sandgrouse)
add_library(http_parser http_parser.c)
add_executable(rsva11001adapter main.c rsva11001.c)
target_link_libraries(rsva11001adapter http_parser ${SANDGROUSE_LIB})
I run the following to set up the make files:
cmake --debug-output -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH="/home/ericu/localdebug" ..
Based on the CMake wiki, setting DCMAKE_PREFIX_PATH does exactly what I want.
CMAKE_PREFIX_PATH
(since CMake 2.6.0) This is used when searching for include files, binaries, or libraries using either the FIND_PACKAGE(), FIND_PATH(), FIND_PROGRAM(), or FIND_LIBRARY() commands. For each path in the CMAKE_PREFIX_PATH list, CMake will check "PATH/include" and "PATH" when FIND_PATH() is called, "PATH/bin" and "PATH" when FIND_PROGRAM() is called, and "PATH/lib" and "PATH" when FIND_LIBRARY() is called. See the documentation for FIND_PACKAGE(), FIND_LIBRARY(), FIND_PATH(), and FIND_PROGRAM() for more details.
However, when I do a 'make VERBOSE=1' this is what I get:
cd /home/ericu/rsva11001adapter/build/src && /usr/bin/gcc -std=gnu99 -g -o CMakeFiles/rsva11001adapter.dir/main.c.o -c /home/ericu/rsva11001adapter/src/main.c
/home/ericu/rsva11001adapter/src/main.c:19:31: fatal error: sandgrouse/server.h: No such file or directory
compilation terminated.
So, it does not seem that CMake is finding things in CMAKE_PREFIX_PATH. It obviously is not adding -I variables to the compiler invocations either.
An inspection of CMakeCache.txt makes it seem as though it has no idea what the variable is:
// No help, variable specified on the command line.
CMAKE_PREFIX_PATH:UNINITIALIZED=/home/ericu/localdebug
I've been working on this for over an hour. I'm nearly at the point of giving up using CMake if it is this difficult to use a non-standard library with it.
You should instruct CMake to add -I flags when compiling your library:
find_path(SANDGROUSE_INCLUDE_DIR sandgrouse/server.h)
include_directories(${SANDGROUSE_INCLUDE_DIR}
Place these lines before add_library() invocation.

Find package Eigen3 for CMake

CMake cannot find my Eigen3 package. I set an environment variable called
EIGEN3_INCLUDE_DIR
pointing to the path where FindEigen3.cmake is.
Then in the CMakelists.txt I wrote:
find_package( Eigen3 REQUIRED )
include_directories( EIGEN3_INCLUDE_DIR )
I get next message of error:
CMake Error at C:/Program Files (x86)/CMake 2.8/share/cmake-2.8/Modules/FindPackageHandleStandardArgs.cmake:91 (MESSAGE):
Could NOT find Eigen3 (missing: EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK)
(Required is at least version "2.91.0")
Call Stack (most recent call first):
C:/Program Files (x86)/CMake 2.8/share/cmake-2.8/Modules/FindPackageHandleStandardArgs.cmake:252 (_FPHSA_FAILURE_MESSAGE)
C:/Program Files (x86)/CMake 2.8/share/cmake-2.8/Modules/FindEigen3.cmake:76 (find_package_handle_standard_args)
test/test_quaternion/CMakeLists.txt:25 (find_package)
Any idea on what I am missing or doing wrong?
Since Eigen3 is completely header only, all you ever need is the path to the include directory. And this one, you are already defining manually anyway. So there is no real need for a FindEigen3.cmake or FIND_PACKAGE call.
Simply use
INCLUDE_DIRECTORIES ( "$ENV{EIGEN3_INCLUDE_DIR}" )
or
SET( EIGEN3_INCLUDE_DIR "$ENV{EIGEN3_INCLUDE_DIR}" )
IF( NOT EIGEN3_INCLUDE_DIR )
MESSAGE( FATAL_ERROR "Please point the environment variable EIGEN3_INCLUDE_DIR to the include directory of your Eigen3 installation.")
ENDIF()
INCLUDE_DIRECTORIES ( "${EIGEN3_INCLUDE_DIR}" )
A few notes:
If you want to access the content of a CMake variable, make sure to use ${...}
$ENV{....} accesses environment variables.
The second example will stop with an error if the environment variable is not set (and, thus, EIGEN3_INCLUDE_DIR cmake variable is empty)
Be careful to use quotation marks around (evaluated) variables if they could contain whitespace. Otherwise, CMake will interpret it as a list.
If you want to use custom find modules, make sure to either place them in you CMake installation or, as #Fraser pointed out above, make sure to point CMAKE_MODULE_PATH to the directory where it is. Not sure, but it could be that CMake checks the current directory as well automatically (where your CMakeLists.txt resides. Anyhow, setting EIGEN3_INCLUDE_DIR is totally unrelated to the location of FindEigen3.cmake
However, it could be that your FindEigen3 script evaluates this variable to determine the location of your Eigen3 installation.
Alternatively, self-built CMake-based projects often provide a <PackageName>Config.cmake. If you point a variable called <PackageName>_DIR to the directory containing this file, you can use FIND_PACKAGE( <PackageName> ...) as normal. See documentation of FIND_PACKAGE for details.
Eigen >= 3.3 has direct CMake integration, so it seems yours isn't set up correctly.
Assume Eigen has been installed to /opt/eigen/3.3 with default settings. Append or prepend the the location /opt/eigen/3.3 to the environment variable CMAKE_PREFIX_PATH e.g in bash:
export CMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH:/opt/eigen/3.3"
Then CMake should pick it up.
If you are writing your own CMakeLists.txt that uses Eigen I suggest using code like this:
find_package (Eigen3 3.3 REQUIRED)
add_executable (example example.cpp)
target_link_libraries (example Eigen3::Eigen)
You should not use include_directories since CMake 3 was released -- the targets approach should be preferred whenever available.
First, make sure Eigen is properly installed. Refer to the INSTALL file that comes with the tarball.
Second, copy the cmake/FindEigen3.cmake file from the tarball to the directory containing your CMakeLists.txt.
In your CMakeLists.txt add:
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
find_package(Eigen3 REQUIRED)
include_directories(${EIGEN3_INCLUDE_DIR})
Now you should be able to do e.g. #include <Eigen/Core>.
All of this comes (mostly) from this source.
This approach has the advantage over e.g. include_directories("$ENV{EIGEN3_INCLUDE_DIR}") that it the uses CMake's standard mechanism for finding external dependencies, making it easier for someone else (or your future self) to pick up the project, possibly on another platform.
(However, it would be nice if Eigen itself installed an EigenConfig.cmake file, making it accessible through the find_package mechanism without any extra paths.)
I found another solution here (which referred to here) which uses the pkg-config file :
find_package(PkgConfig)
pkg_search_module(Eigen3 REQUIRED eigen3)
As a detailed explanation of the note 7 from the top answer of Johannes. By using the "Config mode" rather than "Module mode" of CMake find_packate(), only writing
find_package( Eigen3 REQUIRED )
include_directories( EIGEN3_INCLUDE_DIR )
in CMakeLists.txt is enough.
Please refer to the INSTALL guidance text file contained in the eigen source code directory (eg. extracted from eigen-3.3.7.tar.gz downloaded from official website), which said:
Method 2. Installing using CMake
********************************
Let's call this directory 'source_dir' (where this INSTALL file is).
Before starting, create another directory which we will call 'build_dir'.
Do:
cd build_dir
cmake source_dir
make install
The "make install" step may require administrator privileges.
You can adjust the installation destination (the "prefix")
by passing the -DCMAKE_INSTALL_PREFIX=myprefix option to cmake, as is
explained in the message that cmake prints at the end.
Just like installing usual CMake projects to your machine.
The difference from directly including the /usr/include/eigne3 or /usr/local/include/eigen3 directory is that, a configuration directory called eigen3/cmake will also be installed to /usr/share or usr/local/share. This configuration directory contains the Eigen3Config.cmake file, which can automatically be found by CMake to locate the eigen3 directory.
If you have not added Eigen Library to environment variable then do the following in CMakeLists.txt:
cmake_minimum_required(VERSION 3.9)
project(ProjectName)
set(CMAKE_CXX_STANDARD 11)
# set EIGEN_DIR variable to Eigen Library Path
set(EIGEN_DIR "C:\\Eigendir\\Eigen")
# include the directory
include_directories(${EIGEN_DIR})
add_executable(ProjectName main.cpp)
target_link_libraries(ProjectName ${EIGEN_DIR})
Another simple way that doesn't require adding an environment variable is to simply find eigen with the cmake find_path function https://cmake.org/cmake/help/v3.6/command/find_path.html. The example code finds the directory "Eigen" in paths "/usr/include/" and "/usr/local/include" with an additional search in subdirectory "eigen3".
find_path(EIGEN3_INCLUDE_DIRS "Eigen" paths "/usr/include" "/usr/local/include" path_suffixes "eigen3")
message(${EIGEN3_INCLUDE_DIRS})
if ( NOT EIGEN3_INCLUDE_DIRS )
message(FATAL_ERROR "CMake variable EIGEN3_INCLUDE_DIRS not found.")
endif()
include_directories ( "${EIGEN3_INCLUDE_DIRS}" )
You could try setting the CMAKE_MODULE_PATH to the location of Eigen subdirectory named "cmake":
cmake . -DCMAKE_MODULE_PATH=<Eigen root dir>/cmake/
I had a similar problem when run cmake .. && make on Google Colab on a project clone from github. I fixed it by editing CMakeLists.txt file and adding this line to it:
set(EIGEN3_INCLUDE_DIR "/usr/include/eigen3")
As you can see, my eigen3 was in /usr/include/eigen3 path (and I had installed it using !sudo apt-get install build-essential cmake libeigen3-dev)
When installing on Kubuntu 20.04 following steps from INSTALL:
Do:
cd build_dir
cmake source_dir
make install
using -DCMAKE_INSTALL_PREFIX=/usr/local/eigen-3.4.0 and sudo
FindEigen3.cmake is not installed. However, using
set(Eigen3_DIR "/usr/local/eigen/share/eigen3/cmake")
seem to work. FindEigen3.cmake is in the build directory
but it is not copied to the installation directory tree.
This worked:
Changed c++11 to c++14
Changed find_package(Eigen3 QUIET) to find_package(Eigen3 CONFIG)
Another simple way is:
if the Eigen library is in /opt/eigen/3.3/Eigen
include_directories(/opt/eigen/3.3)
which is equivalent to what Jai suggested
set(EIGEN_DIR "/opt/eigen/3.3")
include_directories(${EIGEN_DIR})
You need to read official documentation:
Click here
After install Eigen from tar and compile it correctly.
CMakeLists.txt will looks like this:
find_package(Eigen3 3.3 REQUIRED NO_MODULE)
add_executable(${PROJECT_NAME} something.cpp)
target_link_libraries(${PROJECT_NAME} Eigen3::Eigen)
It will be fine work.