How to find my generated shared library from cmake? - c++

I want to create a shared library from cmake . I have a simple test.cpp .
My CMakeLists.txt looks like below
cmake_minimum_required(VERSION 2.8)
project (test)
set(CMAKE_BUILD_TYPE Release)
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(test SHARED /home/tuhin/test/test1/test.cpp)
But I am not able to find "test" which my .so, I have seen test.dir folder created but not .so
Please help me to understand the issue.

(I suppose you read the comments and acted accordingly...)
(I also suppose you need a way to find out where your library will be placed, from within CMake build system)
The disk location of any target does not depend on CMakeLists.txt only, but also on the choice of the generator. Multi config generators like Visual Studio something, or Xcode might append configuration name as an additional directory, so you may get different results just by choosing a different generator.
This means that there is no easy way to uniquely identify disk location during configure stage. On the other hand, you may very easily check that information during the build stage:
cmake_minimum_required(VERSION 3.15)
project (lib_file_name)
add_library(my_test_lib SHARED my_test_lib.cpp)
add_custom_target(output_lib_name
ALL
COMMAND ${CMAKE_COMMAND} -E echo "my_test_lib location: $<TARGET_FILE:my_test_lib>"
)
note add_custom_target line:
new target was added, named output_lib_name
it will be executed as a part of building the default target (-> ALL)
command to build this target is asking cmake to output the file name of the target in question, using CMAke generator expressions (--> COMMAND ${CMAKE_COMMAND} -E echo "my_test_lib location: $<TARGET_FILE:my_test_lib>")
If you run it with makefile generator:
$ cmake -S /tmp -B /tmp/make-build -G "Unix Makefiles" ; cmake --build /tmp/make-build
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/make-build
Scanning dependencies of target my_test_lib
[ 50%] Building CXX object CMakeFiles/my_test_lib.dir/my_test_lib.cpp.o
[100%] Linking CXX shared library libmy_test_lib.dylib
[100%] Built target my_test_lib
Scanning dependencies of target output_lib_name
my_test_lib location: /tmp/make-build/libmy_test_lib.dylib
[100%] Built target output_lib_name
Note the line
my_test_lib location: /tmp/make-build/libmy_test_lib.dylib
if you run it with Xcode generator:
configure:
$ cmake -S /tmp -B /tmp/xcode-build -G Xcode
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/xcode-build
build release configuration:
$ cmake --build /tmp/xcode-build --config Release
........... lot of output deleted ...........
my_test_lib location: /tmp/xcode-build/Release/libmy_test_lib.dylib
** BUILD SUCCEEDED **
build debug configuration:
$ cmake --build /tmp/xcode-build --config Debug
........... lot of output deleted ...........
my_test_lib location: /tmp/xcode-build/Debug/libmy_test_lib.dylib
** BUILD SUCCEEDED **
Note how the location is different for different configuration builds, without any change in CMake build system.
At the end, this is the cmake documentation about add_custom_command, cmake generator expressions.

Related

How do I change the name of the executable that I'm installing using CPack?

I do apologize in advanced if this sounds like something trivial. I am new to using CMake and CPack.
I am currently trying to build my own compiler as a side project, and I want to test out how CPack will install my project.
Here is my CMakeLists.txt file that I have at the root of my project folder:
cmake_minimum_required(VERSION 3.15)
project(Simple-C-Compiler VERSION 0.01)
set(CMAKE_CXX_STANDARD 20)
set(COMPILER_VERSION ${PROJECT_VERSION})
add_library(include INTERFACE)
target_include_directories(include INTERFACE include/)
add_subdirectory(lib)
add_subdirectory(phases)
add_subdirectory(compiler)
add_subdirectory(tests)
target_link_libraries(compiler lexer)
target_link_libraries(tester lexer)
add_compile_options(-Wall)
install(TARGETS compiler DESTINATION bin)
set(CPACK_PACKAGE_EXECUTABLES "compiler" "Simple-C")
include(CPack)
When I try to install my compiler, by doing:
mkdir build
cd build
cmake ../
make install
I get the following output:
[ 22%] Built target lib
[ 55%] Built target lexer
[ 77%] Built target compiler
[100%] Built target tester
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/bin/compiler
CPack installed my compiler as "compiler" not "Simple-C". I want the name of the executable being installed to be "Simple-C". How do I go about doing that in my CMakeLists.txt file?
You can change the name of a target with the following command:
set_target_properties(compiler PROPERTIES OUTPUT_NAME Simple-C)
This must be called after the add_subdirectory(compiler)
As a side note, the commands you mentionned did not invoke cpack. In order to invoke cpack, you would need to run the cpack command.
You can use the RENAME option of CMake install. See https://cmake.org/cmake/help/v3.13/command/install.html
In short
install(TARGETS compiler DESTINATION bin RENAME Simple-C)

How to make cmake output to the "build" directory?

I'm using cmake to compile a C++ project, and I want cmake to generate all the output files(metafiles like Makefile used to create binaries) in the build folder. I've checked all the answers in How do I make cmake output into a 'bin' dir?, none of them worked for me(suprisingly!). Files are generated in the root folder instead of in the build folder, what's wrong here? I guess I must have missed something.
Code Structure
➜ cmake-test tree .
.
├── CMakeLists.txt
└── hello.cpp
0 directories, 2 files
CMakeLists.txt
# Specify the minimum version for CMake
cmake_minimum_required(VERSION 3.11)
# Project's name
project(hello)
# Set the output folder where your program will be created
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# The following folder will be included
include_directories("${PROJECT_SOURCE_DIR}")
add_executable(hello ${PROJECT_SOURCE_DIR}/hello.cpp)
Build Commands and Outputs
➜ cmake-test cmake .
-- The C compiler identification is GNU 8.2.0
-- The CXX compiler identification is GNU 8.2.0
-- 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: /home/searene/CLionProjects/cmake-test
➜ cmake-test ls
bin CMakeCache.txt CMakeFiles cmake_install.cmake CMakeLists.txt hello.cpp Makefile
cmake version
➜ cmake-test cmake --version
cmake version 3.11.4
CMake suite maintained and supported by Kitware (kitware.com/cmake).
OS
Linux
The usual way to do this, rather than changing variables to set the path, is simply to create the output directory, change to it, and run cmake from there. So instead of cmake . you usually have cmake .. or similar.
I understand the initial impulse to say "But I expect my build system to write output somewhere else." But CMake is not usually used in the way you were initially expecting, and other people who run your CMake build won't expect what you were expecting, so it's probably best to just use the built-in, default behavior, which is to put the output wherever cmake was run.
Put another way: You are fighting against the tool. Don't do that.
Disclaimer: I recommend going with #john-zwinck's answer.
By default, cmake uses the current working directory as build directory and whatever path you provide as source directory. So the normal way of achieving your goal is
create the build directory (mkdir build)
go there (cd build)
call cmake with the source dir as argument (cmake path/to/source)
BUT there is another way, as far as I know not documented in the cmake docs and only kept for compatibility reasons or internal usage, that some people are using. The -B and -H flags
cmake -Hpath/to/source -Bpath/to/build
or even from the source dir
cmake . -Bbuild
Important: no space after -B.
CMake 3.19.1 (not sure how about older ones) has following option (from docs):
cmake [<options>] -S <path-to-source> -B <path-to-build>
Uses as the build tree and as the
source tree. The specified paths may be absolute or relative to the
current working directory. The source tree must contain a
CMakeLists.txt file. The build tree will be created automatically if
it does not already exist. For example:
cmake -S src -B build

make: *** No targets specified and no makefile found. Stop. [ubuntu]

I'm trying to build this
https://github.com/patrikhuber/eos
but I'm having troubles.
The instructions are pretty simple, as it says on gitHub
To build:
git clone --recursive https://github.com/patrikhuber/eos.git
mkdir build && cd build # creates a build directory next to the 'eos' folder
cmake -G "<your favourite generator>" ../eos -DCMAKE_INSTALL_PREFIX=../install/
make && make install # or open the project file and build in an IDE like Visual Studio
I'm using "Ninja" as generator and it looks like the cmake part goes through successfully as I get
-- Configuring done
-- Generating done
-- Build files have been written to: /home/francesco/eos/build
That's where things stop "working" for me, or where I fail to understand what's next. Following the instructions, I type
make && make install
and I get this message
make: *** No targets specified and no makefile found. Stop.
I looked around for solutions but I don't really understand what I am supposed to do: I tried
./configure
but I'm getting
bash: ./configure: No such file or directory
Anyone can please help?
Thanks
It always depends on your CMake "Generator". The 'make' is linux/mingw tool/command. For VisualStudio you can use nmake or sln/proj generated stuff.
More reliable could be utilize CMake for building i.e. for "NMake Makefiles" generator:
cmake --build <build folder> --target install
or
cmake --build <build folder> --config release --target install
for VisualStudio generator
I had the same problem, and solved by tinkering with locations for cmake and make. Here's what I used:
cmake -DCMAKE_INSTALL_PREFIX=/usr/local
make
I believe /usr/local is the default location (see here)

CMake install target dependencies

I am writing a library that contains library itself and examples and I am using CMake:
cmake_minimum_required(VERSION 3.6)
add_executable (example main.cpp)
install(DIRECTORY include DESTINATION include PATTERN ".DS_Store" EXCLUDE)
When I am running cmake --build . --target install - it compiles example target and makes installation of include directory
I want to exclude building example target and make only include directory installation when building install target and building example if running without any special target:
Here I want example to be NOT built:
cmake --build . --target install
Here I want example to be built:
cmake --build .
How should I change my CMakeLists.txt to make it work as I want?
You cannot exclude single CMake target when installing.
The problem is that 'install' target may depends only from 'all' (default) target.
While you may remove 'install' -> 'all' dependency (by setting CMAKE_SKIP_INSTALL_ALL_DEPENDENCY variable), you may not add another dependency for 'install'.
So, before installing
cmake --build . --target install
either performs
cmake --build .
or doesn't build anything (even library, which you want to build in any case).

How to use the tool include-what-you-use together with CMake to detect unused headers?

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.