I am struggling with cmake-baed boost linking problem that I searched on stackoverflow, and on other forums but to no avail.
I am compiling a C++ program suite (depending on different libraries, in addition to Boost) on a cluster where Boost is already installed (and I know the full path). After getting weird linking errors for boost with cmake while compiling, I thought of first compiling a very simple boost-cmake example to solve the problem.
The code is given below.
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/option.hpp>
using namespace std;
#include <iostream>
namespace po = boost::program_options;
int main(int argc, char** argv) {
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce help message")
;
return 0;
}
I am using the following CMakeLists.txt file for building.
cmake_minimum_required(VERSION 2.8)
set(Boost_INCLUDE_DIR /software/apps/boost/1.55.0/build06/include)
set(Boost_LIBRARY_DIR /software/apps/boost/1.55.0/build06/lib)
find_package(Boost COMPONENTS program_options REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
link_directories(${Boost_LIBRARY_DIR})
message("Boost include dir is ${Boost_INCLUDE_DIR}")
message("Boost library dir is ${Boost_LIBRARY_DIR}")
message("Boost libraries are at ${Boost_LIBRARIES}")
add_executable(main main.cpp)
target_link_libraries( main ${Boost_LIBRARIES} )
When I compile using cmake, I get the following output
x_ikrul#ikramu build]$ emacs ../CMakeLists.txt
Display localhost:39.0 unavailable, simulating -nw
[x_ikrul#triolith1 build]$ rm -rf *
[x_ikrul#triolith1 build]$ cmake ..
-- The C compiler identification is GNU 4.7.2
-- The CXX compiler identification is GNU 4.7.2
-- Check for working C compiler: /software/apps/comp_wrapper/gnu/gcc
-- Check for working C compiler: /software/apps/comp_wrapper/gnu/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /software/apps/comp_wrapper/gnu/c++
-- Check for working CXX compiler: /software/apps/comp_wrapper/gnu/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
Boost found.
Found Boost components:
program_options
Boost include dir is /usr/include
Boost library dir is /software/apps/boost/1.55.0/build06/lib
Boost libraries are at optimized;boost_program_options-mt-shared;debug;boost_program_options-mt-shared-debug
-- Configuring done
-- Generating done
-- Build files have been written to: /home/x_ikrul/Downloads/boost_example/build
THE PROBLEM comes when I "make" the code as given below.
x_ikrul#ikramu build]$make
Scanning dependencies of target main
[100%] Building CXX object CMakeFiles/main.dir/main.cpp.o
make[2]: *** No rule to make target `/usr/lib64/lib64/libboost_program_options-mt.so.5', needed by `main'. Stop.
make[1]: *** [CMakeFiles/main.dir/all] Error 2
make: *** [all] Error 2
As you may see, although CMake shows the lib directory for boost to be /software/apps/boost/1.55.0/build06/lib, strangely at linking time, it is referring to a different non-exising directory.
Anybody came across error like this? The cluster is running CentOS release 6.5, the boost (where I am pointing) is 1.55.0 and the cmake I am using is 2.8.8.
You're not setting the hint paths correctly.
From the FindBoost module docs:
This module reads hints about search locations from variables:
BOOST_ROOT - Preferred installation prefix
(or BOOSTROOT)
BOOST_INCLUDEDIR - Preferred include directory e.g. <prefix>/include
BOOST_LIBRARYDIR - Preferred library directory e.g. <prefix>/lib
Boost_NO_SYSTEM_PATHS - Set to ON to disable searching in locations not
specified by these hint variables. Default is OFF.
...
and saves search results persistently in CMake cache entries:
Boost_INCLUDE_DIR - Directory containing Boost headers
Boost_LIBRARY_DIR - Directory containing Boost libraries
So, your lines:
set(Boost_INCLUDE_DIR /software/apps/boost/1.55.0/build06/include)
set(Boost_LIBRARY_DIR /software/apps/boost/1.55.0/build06/lib)
aren't actually setting hint variables - you want to be setting BOOST_INCLUDEDIR and BOOST_LIBRARYDIR; possibly also Boost_NO_SYSTEM_PATHS.
This is best not hard-coded inside your CMakeLists.txt since that's not portable. Rather pass these on the command line when invoking CMake:
cmake . -DBOOST_INCLUDEDIR=/software/apps/boost/1.55.0/build06/include -DBOOST_LIBRARYDIR=/software/apps/boost/1.55.0/build06/lib -DBoost_NO_SYSTEM_PATHS=ON
You can also get a much better idea of what's going on if you set Boost_DEBUG to ON.
As an aside, you shouldn't need the link_directories call since the full paths to the Boost libs are passed in the target_link_libraries call.
This stackoverflow answer suggests adding -DBoost_NO_BOOST_CMAKE=ON on the cmake command line.
It seems to be caused by the fact that some CMake versions do not work well with some Boost versions.
And I agree to what user Fraser said. These lines do not make sense
set(Boost_INCLUDE_DIR /software/apps/boost/1.55.0/build06/include)
set(Boost_LIBRARY_DIR /software/apps/boost/1.55.0/build06/lib)
as those variables are used by CMake to store the result from the Boost search. Read more about it in his answer.
Related
I've searched high and low for this answer and I think it should be answered in a modern setting. Most things I see are from 2013 or at the latest 2015 with comments from 2019.
to start off I am using macOS 11.2 with the most recent version of xcode 12.4.
I cloned and installed from git the most recent (as of today) repositories for boost and emscripten.
for some reason on my project when trying to integrate enscripten flags into my CMakeLists.txt file I get an error running
$ cmake .. then $ make.
the CMakeLists.txt file:
cmake_minimum_required(VERSION 3.17)
project(FernQuest) #emscripten version
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
message(STATUS "using emscripten")
endif ()
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
message(STATUS "using cmake")
endif ()
#options
option(JS_ONLY "Compiles to native JS (No WASM)" OFF)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/out)
include_directories(.)
include_directories(/usr/local/include) #where boost in located
message(STATUS "finding boost!")
find_package(Boost 1.74.0 REQUIRED serialization system filesystem COMPONENTS serialization system filesystem)
if(Boost_FOUND)
message(STATUS "found boost!")
endif()
include_directories(${Boost_INCLUDE_DIR})
link_directories(${Boost_LIBRARY_DIR})
if(NOT Boost_FOUND)
message(FATAL_ERROR "Could not find boost!")
endif()
message(STATUS "setting sources")
SET(FQ_SRCS
../src/FernQuest.cpp
../src/Item.cpp
../src/Item.h
../src/Player.cpp
../src/Player.h
../src/Game.cpp
../src/Game.h
../src/QuestLog.cpp
../src/QuestLog.h)
SET(CMAKE_C_COMPILER emcc)
SET(CMAKE_CPP_COMPILER em++)
add_executable(FernQuest ${FQ_SRCS})
if(Boost_FOUND)
if(JS_ONLY)
message(STATUS "Setting compilation target to native JavaScript")
set(CMAKE_EXECUTABLE_SUFFIX ".js")
set_target_properties(FernQuest PROPERTIES COMPILE_FLAGS "-s USE_BOOST_HEADERS=1" LINK_FLAGS "-s USE_BOOST_HEADERS=1 -s WASM=0 -s EXPORTED_FUNCTIONS='[_main]'")
else(JS_ONLY)
message(STATUS "Setting compilation target to WASM")
set(CMAKE_EXECUTABLE_SUFFIX ".wasm.js")
set_target_properties(FernQuest PROPERTIES COMPILE_FLAGS "-s USE_BOOST_HEADERS=1" LINK_FLAGS " -s USE_BOOST_HEADERS=1 -s WASM=1 -s EXPORTED_FUNCTIONS='[_main]'")
endif(JS_ONLY)
endif()
the error:
-- The C compiler identification is AppleClang 12.0.0.12000032
-- The CXX compiler identification is AppleClang 12.0.0.12000032
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- using cmake
-- finding boost!
-- Found Boost: /usr/local/lib/cmake/Boost-1.76.0/BoostConfig.cmake (found suitable version "1.76.0", minimum required is "1.74.0") found components: serialization system filesystem serialization system filesystem
-- found boost!
-- setting sources
-- Setting compilation target to WASM
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/codiecottrell/Documents/FernQuest/emscripten/build
Scanning dependencies of target FernQuest
[ 16%] Building CXX object CMakeFiles/FernQuest.dir/Users/codiecottrell/Documents/FernQuest/src/FernQuest.cpp.o
clang: error: no such file or directory: 'USE_BOOST_HEADERS=1'
make[2]: *** [CMakeFiles/FernQuest.dir/Users/codiecottrell/Documents/FernQuest/src/FernQuest.cpp.o] Error 1
make[1]: *** [CMakeFiles/FernQuest.dir/all] Error 2
make: *** [all] Error 2
so I read up and they say that to fix this you use this below as to actually run it using the -DCMAKE_TOOLCHAIN_FILE:
$ emcmake cmake .. then $ emmake make
this error occurs:
configure: cmake .. -DCMAKE_TOOLCHAIN_FILE=/Users/codiecottrell/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_CROSSCOMPILING_EMULATOR="/Users/codiecottrell/emsdk/node/14.15.5_64bit/bin/node"
-- using emscripten
-- finding boost!
CMake Error at /usr/local/Cellar/cmake/3.19.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:218 (message):
Could NOT find Boost (missing: Boost_INCLUDE_DIR serialization system
filesystem serialization system filesystem) (Required is at least version
"1.74.0")
Call Stack (most recent call first):
/usr/local/Cellar/cmake/3.19.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:582 (_FPHSA_FAILURE_MESSAGE)
/usr/local/Cellar/cmake/3.19.4/share/cmake/Modules/FindBoost.cmake:2193 (find_package_handle_standard_args)
CMakeLists.txt:21 (find_package)
-- Configuring incomplete, errors occurred!
See also "/Users/codiecottrell/Documents/FernQuest/emscripten/build/CMakeFiles/CMakeOutput.log".
make: make
-- using emscripten
-- finding boost!
CMake Error at /usr/local/Cellar/cmake/3.19.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:218 (message):
Could NOT find Boost (missing: Boost_INCLUDE_DIR serialization system
filesystem serialization system filesystem) (Required is at least version
"1.74.0")
Call Stack (most recent call first):
/usr/local/Cellar/cmake/3.19.4/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:582 (_FPHSA_FAILURE_MESSAGE)
/usr/local/Cellar/cmake/3.19.4/share/cmake/Modules/FindBoost.cmake:2193 (find_package_handle_standard_args)
CMakeLists.txt:21 (find_package)
-- Configuring incomplete, errors occurred!
See also "/Users/codiecottrell/Documents/FernQuest/emscripten/build/CMakeFiles/CMakeOutput.log".
make: *** [cmake_check_build_system] Error 1
My Question:
it seems that enscripten cannot find boost when running it through its own means, however cmake can clearly find it. There is also support for running boost through emscripten as I've read in both documentations however there is no clear way. What is this way and where am I going wrong? I'm going to continue to troubleshoot
EDIT
just tried $ emconfigure ./b2 toolset=gcc --prefix=/usr/local/B2
and it didn't change anything
If you're building with emscripten then the libraries on your mac (where cmake is searching) won't work; you will need to compile them statically.
I recommend trying to build your project without CMake.
If you're project only uses the boost headers (not libraries), then something like this might work:
$ em++ ../src/*.cpp -o index.html -s USE_BOOST_HEADERS=1
Otherwise you'll need to compile Boost also. Once you've done that and you have a libboost.a file, you'd compile your program like this:
$ em++ ../src/*.cpp -c -s USE_BOOST_HEADERS=1
Then link it:
$ em++ *.o /path/to/libboost.a -o index.html
Of course, depending on what other libraries you use you'll need to tweak those commands. But the general idea is to compile all the dependencies into static archive (.a) files, then compile those together to get the resulting .html (or .js or .wasm) file.
Read more about compiling with emcc.
Now that I've looked through other peoples solutions for several hours and could not find quite the right answer for my problem I would like to bring my specific problem to you. :)
I am trying to build vsomeip with CMake. For that I previously built boost 1.55, however, I get the following errors in CMake:
The C compiler identification is MSVC 19.0.24215.1
The CXX compiler identification is MSVC 19.0.24215.1
Check for working C compiler: C:/Program Files (x86)/Microsoft Visua Studio 14.0/VC/bin/cl.exe
Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/cl.exe -- works
Detecting C compiler ABI info
Detecting C compiler ABI info - done
Detecting C compile features
Detecting C compile features - done
Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/cl.exe
Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/cl.exe -- works
Detecting CXX compiler ABI info
Detecting CXX compiler ABI info - done
Detecting CXX compile features
Detecting CXX compile features - done
Setting build type to 'RelWithDebInfo' as none was specified.
Looking for pthread.h
Looking for pthread.h - not found
Found Threads: TRUE
CMake Error at C:/Program Files/CMake/share/cmake-3.12/Modules/FindBoost.cmake:2025 (message):
Unable to find the requested Boost libraries.
Boost version: 1.55.0
Boost include path: C:/Program Files/boost/boost_1_55_0
Could not find the following static Boost libraries:
boost_system
boost_thread
boost_log
Some (but not all) of the required Boost libraries were found. You may
need to install these additional Boost libraries. Alternatively, set
BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT
to the location of Boost.
Call Stack (most recent call first):
CMakeLists.txt:99 (find_package)
Boost was not found!
Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)
Systemd was not found, watchdog disabled!
using MSVC Compiler
Predefined unicast address: 127.0.0.1
Predefined diagnosis address: 0x00
Predefined routing application: vsomeipd
Could NOT find Doxygen (missing: DOXYGEN_EXECUTABLE)
CMake Warning at CMakeLists.txt:335 (message):
Doxygen is not installed. Documentation can not be built.
CMake Warning at CMakeLists.txt:374 (message):
asciidoc is not installed. Readme can not be built.
GTEST_ROOT is not defined. For building the tests the variable
GTEST_ROOT has to be defined. Tests can not be built.
Configuring incomplete, errors occurred!
See also "D:/Desktop/BACHELORARBEIT/vsomeip/build/CMakeFiles /CMakeOutput.log".
See also "D:/Desktop/BACHELORARBEIT/vsomeip/build/CMakeFiles/CMakeError.log".
It cannot find the static Boost libraries. Now, I've tried playing around with the CMakeList.txt and here is the part of it that would be supposed to handle the linking:
# Boost
set(BOOST_INCLUDE_DIR C:/Program Files/Boost/boost_1_55_0)
set(BOOST_LIBRARYDIR C:/Program Files/Boost/boost_1_55_0/stage/libs)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
find_package( Boost 1.55 COMPONENTS system thread log REQUIRED )
include_directories( ${Boost_INCLUDE_DIR} )
if(Boost_FOUND)
if(Boost_LIBRARY_DIR)
MESSAGE( STATUS "Boost_LIBRARY_DIR not empty using it: ${Boost_LIBRARY_DIR}" )
else()
if(BOOST_LIBRARYDIR)
MESSAGE( STATUS "Boost_LIBRARY_DIR empty but BOOST_LIBRARYDIR is set setting Boost_LIBRARY_DIR to: ${BOOST_LIBRARYDIR}" )
set(Boost_LIBRARY_DIR ${BOOST_LIBRARYDIR})
endif()
endif()
else()
MESSAGE( STATUS "Boost was not found!")
endif()
I have also tried using a newer boost version (1.67) with same results. Any help will be dearly appreciated!
Check if your compiled libraries are in the following directory:
C:/Program Files/Boost/boost_1_55_0/stage/libs
If not, set your lib folder directory path:
set(BOOST_LIBRARYDIR path_to_lib_directory)
As #Tsyvarev suggested I used set(Boost_DEBUG ON) to trace the exact locations and files that CMake was looking for and the discovered several problems:
1.) Setting the path to "C:/Program Files/Boost/boost_1_55_0"
causes problems, because of the space in the path
2.) It searched for the libraries covering multiple formats like: boost_thread-vc141-mt-gd-x32-1_55.lib.
However, when I built boost with incorrect parameters, so my libs were built like this:
libboost_thread-vc-mt-1_55.lib, which is not of the correct format.
3.) Unfortunately adding other options when building boost, e.g.:
b2 toolset=msvc-14.1 address-model=32 --build-type=complete
caused other errors. Also building boost_1_67_0 manually worked for me at all.
My solution to the problem was to simply take one of the third-party download( https://dl.bintray.com/boostorg/release/1.67.0/binaries/). This way all the libraries were built correctly and I had no trouble linking to them.
Situation:
I have a Windows 7 machine with OpenCV for Windows installed on it.
My OpenCV C++ projects work fine with Visual Studio 2010.
I want to run my existing OpenCV C++ projects to run on Raspberry Pi and on other Linux machines.
Trouble
As a first step, I am trying to compile my .cpp & .h files using GCC on Cygwin on my Windows Machine. For this purpose I am trying to use CMake package for Cygwin, but CMake gives error that it cannot find OpenCV package. (error is listed below).
Question:
Do i need to install OpenCV package for Cygwin separately for CMake to work ?
Is there a way to using my existing OpenCV for Win to work with CMake ?
What environment variables need to be set ?
(Currently only a variable OPENCV_DIR is set to C:/opencv/build)
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.4)
PROJECT (testProj)
find_package(OpenCV REQUIRED )
set( NAME_SRC
src/main.cpp
src/imgProcess.cpp
)
set( NAME_HEADERS
include/imgProcess.h
)
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/include )
link_directories( ${CMAKE_BINARY_DIR}/bin)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
add_executable( testProj ${NAME_SRC} ${NAME_HEADERS} )
target_link_libraries( test ${OpenCV_LIBS} )
cmake error
$ cmake .
-- The C compiler identification is GNU 4.9.3
-- The CXX compiler identification is GNU 4.9.3
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++.exe
-- Check for working CXX compiler: /usr/bin/c++.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Error at CMakeLists.txt:3 (find_package):
By not providing "FindOpenCV.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "OpenCV", but
CMake did not find one.
Could not find a package configuration file provided by "OpenCV" with any
of the following names:
OpenCVConfig.cmake
opencv-config.cmake
Add the installation prefix of "OpenCV" to CMAKE_PREFIX_PATH or set
"OpenCV_DIR" to a directory containing one of the above files. If "OpenCV"
provides a separate development package or SDK, be sure it has been
installed.
-- Configuring incomplete, errors occurred!
See also "/cygdrive/c/Work/Project/cmaketest/CMakeFiles/CMakeOutput.log".
The variable should be called OpenCV_DIR, it must have the same capitalization as in find_package(OpenCV REQUIRED).
As #berak, stated in the comment, I installed OpenCV Package for Cygwin using Cygwin Ports. (Without any src or requiring any build, simple install only).
Had to tweak my CMakeLists.txt a little but it compiled well.
##### CMakeLists.txt ########
cmake_minimum_required(VERSION 2.8.4)
PROJECT (test)
find_package(OpenCV REQUIRED )
set( NAME_SRC
src/main.cpp
src/mytest.cpp
)
set( NAME_HEADERS
include/mytest.hpp
)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
add_executable( test ${NAME_SRC} ${NAME_HEADERS} )
include_directories(/usr/include /usr/include/opencv2 /usr/include/opencv ${CMAKE_CURRENT_SOURCE_DIR}/include)
link_directories(/usr/lib ${CMAKE_BINARY_DIR}/bin)
target_link_libraries(test opencv_core opencv_highgui opencv_imgproc)
(Now, I have totally different trouble of runtime error : Gtk-WARNING **: cannot open display, but its another story of not having XServer on Cygwin)
First take the following steps to build opencv using visual studio and cmake gui.
Clone into the opencv source code repo
$ git clone https://github.com/Itseez/opencv.git
Navigate inside the folder and checkout to the specified version
$ git checkout 3.0.0
Create a build directory and build opencv in there using CMake and visual studio. Note that by default opencv will build dynamic libraries unless you enable the option of building opencv static libraries.
Once done you should handle the environment variables. Create a variable named OpenCV_DIR and point it to the build directory of opencv. Then update your PATH variable to have new opencv dll files added. Usually they can be found in the directory opencv\build\bin\Release assuming you have built opencv in Release mode
Then set up your project CMakeList.txt as follows
find_package(OpenCV REQUIRED)
include_directories(
${OpenCV_INCLUDE_DIRS}
)
target_link_libraries(test
${OpenCV_LIBS}
)
The command find_package(OpenCV REQUIRED) finds the opencv configuration files in the directory "opencv/build", aka the directory in which you have built opencv (That's why you should set the value of the variable ${OpenCV_DIR} to this directory so the command find_package can find the required files in there).
The two variables {OpenCV_INCLUDE_DIRS} and ${OpenCV_LIBS} have already been set in those configuration files. So you should be all set.
The tool include-what-you-use can be used to detect unneeded headers. I am using CMake for my C++ software project. How can I instruct CMake to run include-what-you-use automatically on the source files of my software project?
CMake 3.3 introduced the new target property CXX_INCLUDE_WHAT_YOU_USE that can be set to the path of the program include-what-you-use. For instance this CMakeLists.txt
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
add_executable(hello main.cc)
find_program(iwyu_path NAMES include-what-you-use iwyu REQUIRED)
# If using CGAL<3.18, you remove REQUIRED and use
# if(NOT iwyu_path)
# message(FATAL_ERROR "Could not find the program include-what-you-use")
# endif()
set_property(TARGET hello PROPERTY CXX_INCLUDE_WHAT_YOU_USE ${iwyu_path})
is able to build the file main.cc
#include <iostream>
#include <vector>
int main() {
std::cout << "Hello World!" << std::endl;
return 0;
}
and at the same time have include-what-you-use give out a warning that
the included header vector is not needed.
user#ubuntu:/tmp$ ls ~/hello
CMakeLists.txt main.cc
user#ubuntu:/tmp$ mkdir /tmp/build
user#ubuntu:/tmp$ cd /tmp/build
user#ubuntu:/tmp/build$ ~/cmake-3.3.0-rc2-Linux-x86_64/bin/cmake ~/hello
-- The C compiler identification is GNU 4.9.2
-- The CXX compiler identification is GNU 4.9.2
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/build
user#ubuntu:/tmp/build$ make
Scanning dependencies of target hello
[ 50%] Building CXX object CMakeFiles/hello.dir/main.cc.o
Warning: include-what-you-use reported diagnostics:
/home/user/hello/main.cc should add these lines:
/home/user/hello/main.cc should remove these lines:
- #include <vector> // lines 2-2
The full include-list for /home/user/hello/main.cc:
#include <iostream> // for operator<<, basic_ostream, cout, endl, ostream
---
[100%] Linking CXX executable hello
[100%] Built target hello
user#ubuntu:/tmp/build$ ./hello
Hello World!
user#ubuntu:/tmp/build$
If you want to pass custom options to include-what-you-use, like for instance --mapping_file you can do it via
set(iwyu_path_and_options
${iwyu_path}
-Xiwyu
--mapping_file=${my_mapping})
set_property(TARGET hello
PROPERTY CXX_INCLUDE_WHAT_YOU_USE ${iwyu_path_and_options})
If you don't have access to CMake 3.3, include-what-you-use comes with a python tool called iwyu_tool.py which can do what you want.
It works by parsing a JSON compilation database, which is easily produced with CMake (see below).
Running the tool manually
Assuming you already have a CMake build dir for your project, you first need to tell CMake to produce the compilation database:
$ cd build
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
This generates a file, compile_commands.json containing compiler invocations for every object file in your project. You don't need to rebuild the project.
You can now run include-what-you-use on your project by running the python tool on your build directory:
$ python /path/to/iwyu_tool.py -p .
Adding a custom target to your cmake project
The following snippet can be used to add an iwyu target to a cmake project.
# Generate clang compilation database
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
find_package(PythonInterp)
find_program(iwyu_tool_path NAMES iwyu_tool.py)
if (iwyu_tool_path AND PYTHONINTERP_FOUND)
add_custom_target(iwyu
ALL # Remove ALL if you don't iwyu to be run by default.
COMMAND "${PYTHON_EXECUTABLE}" "${iwyu_tool_path}" -p "${CMAKE_BINARY_DIR}"
COMMENT "Running include-what-you-use tool"
VERBATIM
)
endif()
Notes
The include-what-you-use binary needs to be in your path for any of the above to work properly.
By default, iwyu_tool.py is single-threaded, which can be slow for large projects. You can use the --jobs argument to increase the number of source files that will be processed in parallel.
You can also enable it globally outside the cmake script by setting the cmake variable:
cmake -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="iwyu" <builddir>
It will then call it on each CXX target.
I extended the source code from Alastair Harrison, in order to create a reusable solution. I've came up with the following that should work with all CMake versions:
File iwyu.cmake:
#.rst:
# include-what-you-use (iwyu)
# ----------------------------
#
# Allows to run the static code analyzer `include-what-you-use (iwyu)
# <http://include-what-you-use.org>`_ as a custom target with the build system
# `CMake <http://cmake.org>`_.
#
# .. topic:: Dependencies
#
# This module requires the following *CMake* modules:
#
# * ``FindPythonInterp``
#
# .. topic:: Contributors
#
# * Florian Wolters <wolters.fl#gmail.com>
#===============================================================================
# Copyright 2015 Florian Wolters
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#===============================================================================
# ------------------------------------------------------------------------------
# Include guard for this file.
# ------------------------------------------------------------------------------
if(iwyu_included)
return()
endif()
set(iwyu_included TRUE)
option(BUILD_IWYU
"Run the include-what-you-use static analyzer on the source code of the project."
OFF)
function(iwyu_enable)
set(iwyu_EXECUTABLE_NAME include-what-you-use)
find_program(iwyu_EXECUTABLE ${iwyu_EXECUTABLE_NAME})
if(iwyu_EXECUTABLE)
# This is not exactly the same behavior as with CMake v3.3, since here all
# compiled targets are analyzed.
set(iwyu_tool_EXECUTABLE_NAME iwyu_tool.py)
find_package(PythonInterp)
find_program(iwyu_tool_EXECUTABLE ${iwyu_tool_EXECUTABLE_NAME})
if(PYTHONINTERP_FOUND AND iwyu_tool_EXECUTABLE)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON PARENT_SCOPE)
add_custom_target(iwyu
ALL
COMMAND "${PYTHON_EXECUTABLE}" "${iwyu_tool_EXECUTABLE}" -p "${CMAKE_BINARY_DIR}"
COMMENT "Running the ${iwyu_tool_EXECUTABLE_NAME} compilation database driver"
VERBATIM)
else()
message(STATUS
"Unable to find the Python interpreter and/or the ${iwyu_tool_EXECUTABLE_NAME} script")
endif()
else()
message(STATUS "Unable to find the ${iwyu_EXECUTABLE_NAME} executable")
endif()
endfunction()
File CMakeLists.txt:
cmake_minimum_required(VERSION 3.0)
include(iwyu.cmake)
project(hello_world)
add_executable(${PROJECT_NAME} main.cc)
if(BUILD_IWYU)
iwyu_enable()
endif()
Invoke CMake as follows to run include-what-you-use when the all target is invoked:
cmake -DBUILD_IWYU=ON <path-to-source>
cmake --build . --target all
The output should be as follows:
-- Configuring done
-- Generating done
-- Build files have been written to: /home/wolters/workspace/include-what-you-use_example/build
[ 66%] Built target hello_world
[100%] Running the iwyu_tool.py compilation database driver
/home/wolters/workspace/include-what-you-use_example/develop/main.cc should add these lines:
/home/wolters/workspace/include-what-you-use_example/develop/main.cc should remove these lines:
- #include <vector> // lines 1-1
The full include-list for /home/wolters/workspace/include-what-you-use_example/develop/main.cc:
#include <iostream> // for operator<<, basic_ostream, cout, endl, ostream
---
[100%] Built target iwyu
Edit 2015-08-19: The approach with the CMake property <LANG>_INCLUDE_WHAT_YOU_USE did not work for me with CMake version 3.3.1. Therefore I updated the solution.
Edit 2015-09-30: The output was wrong, since my include-what-you-use installation was broken. The include-what-you-use and iwyu_tool.py files have to be in the same directory as clang, clang++, etc.
I have compiled Boost 1.51.0 on Windows using the rubenvb's CLang build. I actually compiled b2 using MinGW:
bootstrap mingw
... compiling b2 using mingw...
and then I compiled the libraries with CLang:
b2 toolset=clang stage --stagedir=. --build-type=complete --with-regex ...
By the way, even if I specified --build-type=complete there are no DLLs in lib directory, but I read somewhere that CLang has still problem with linking on Windows so that might be the reason. Anyway static libraries are fine for me. I got these files in %BOOST_ROOT%\lib:
libboost_regex-clang31-1_51.lib
libboost_regex-clang31-d-1_51.lib
libboost_regex-clang31-mt-1_51.lib
libboost_regex-clang31-mt-d-1_51.lib
libboost_regex-clang31-mt-s-1_51.lib
libboost_regex-clang31-mt-sd-1_51.lib
libboost_regex-clang31-s-1_51.lib
libboost_regex-clang31-sd-1_51.lib
Now, if I compile something with CLang from command line everything works. The problem shows when I try to make CMake find Boost libraries: it simply could not find them. I tried with this CMakeFiles.txt:
cmake_minimum_required (VERSION 2.8)
project(ccc)
# Setting/unsetting this does not change anything.
set(Boost_USE_STATIC_LIBS ON)
find_package(Boost COMPONENTS regex REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
link_directories(${Boost_LIBRARY_DIRS})
add_executable(ccc main.cpp)
target_link_libraries(ccc
${Boost_REGEX_LIBRARY}
)
Building it using MinGW (and a MinGW compiled version of Boost) it works. If I try with CLang (after having setted CC=clang, CXX=clang++ and BOOST_ROOT=C:/misc/boost/clang-1_51_0) it does not:
D:\Desktop\ppp>cmake -G "MinGW Makefiles" ..\ccc
-- The C compiler identification is Clang 3.1.0
-- The CXX compiler identification is Clang 3.1.0
-- Check for working C compiler: C:/misc/clang/bin/clang.exe
-- Check for working C compiler: C:/misc/clang/bin/clang.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: C:/misc/clang/bin/clang++.exe
-- Check for working CXX compiler: C:/misc/clang/bin/clang++.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
CMake Error at C:/misc/cmake/share/cmake-2.8/Modules/FindBoost.cmake:1191 (message):
Unable to find the requested Boost libraries.
Boost version: 1.51.0
Boost include path: C:/misc/boost/clang-1_51_0
The following Boost libraries could not be found:
boost_regex
No Boost libraries were found. You may need to set BOOST_LIBRARYDIR to the
directory containing Boost libraries or BOOST_ROOT to the location of
Boost.
Call Stack (most recent call first):
CMakeLists.txt:5 (find_package)
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
Boost_REGEX_LIBRARY (ADVANCED)
linked by target "ccc" in directory D:/Desktop/ccc
-- Configuring incomplete, errors occurred!
However, if I compile manually it works again:
clang++ main.cpp -I%BOOST_ROOT% -L%BOOST_ROOT%\lib -llibboost_regex-clang31-1_51
...Ok, and the executable works
Manually setting BOOST_LIBRARYDIR does not work either. Neither does using backslashes \.
Looking inside the file "C:/misc/cmake/share/cmake-2.8/Modules/FindBoost.cmake" you can find a list of all the variables related to Boost you can use. The one you need is Boost_COMPILER (Boost_DETAILED_FAILURE_MSG can also be useful to diagnose problems):
# Boost_COMPILER Set this to the compiler suffix used by Boost
# (e.g. "-gcc43") if FindBoost has problems finding
# the proper Boost installation