set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON)
You are trying to clean your SCons build using
scons clean
but you see the following error message:
scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... scons: *** Do not know how to make File target `clean' (/home/user/myproject/clean). Stop. scons: building terminated because of errors.
When using SCons, the correct command to clean is
scons --clean
You can force SCons to provide colored output when using GCC or G++ by adding
-fdiagnostics-color=always
to your CFLAGS
or CXXFLAGS
. Typically, my recommendation is to add it to both CFLAGS
and CXXFLAGS
.
# CMake generated files build/ CMakeCache.txt CMakeFiles/ Makefile cmake_install.cmake install_manifest.txt
It is often helpful to include the current directory for C++ projects. When using GCC directly, this can be done using -I.
, whereas for CMake you need to use the following statement:
target_include_directories(myexe PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
Remember to replace myexe
by the name of your executable target.
You are trying to build your CMake-based project using a CMakeLists.txt
like
cmake_minimum_required(VERSION 3.10) project(my_project) add_executable(my_project *.cpp)
You can’t use the glob pattern *.cpp
directly in add_executable()
. You need to use file(GLOB ...)
in order to set a variable, which you can then use in add_executable()
:
cmake_minimum_required(VERSION 3.10) project(my_project) file(GLOB SRC_FILES *.cpp) add_executable(my_project ${SRC_FILES})
In your CMakeLists.txt
, you want to add an include directory such as /usr/include/mylibrary
for the executable myexe
using code like:
target_include_directories( myexe /usr/include/mylib )
But when you try to configure the build using cmake .
or make
, you see an error message like
CMake Error at CMakeLists.txt:8 (target_include_directories): target_include_directories called with invalid arguments -- Configuring incomplete, errors occurred!
You need to add PUBLIC
between the target name (myexe
) and the include directory/directories:
target_include_directories( myexe PUBLIC /usr/include/mylib )
This is the .gitignore
I use for most of my conan
-built executable projects:
CMakeCache.txt CMakeFiles/ Makefile bin/ cmake_install.cmake conan.lock conanbuildinfo.cmake conanbuildinfo.txt conaninfo.txt graph_info.json
It is debatable whether you should include lock files such as conan.lock
. My opinion is that in the development phase they should be ignored but reconsidered when entering into production service.
In the directory where you want to create the project, run (obviously, replace mypackage
by the name of everywhere in our code!)
conan new mypackage/1.0.0 -s
-s
is important here. It tells conan that the source is available in the project directory and it should not be pulled using git etc.
This will initialize a shared library project, which we will now modify to build an executable.
First, open src/CMakeLists.txt
and change add_library()
to add_executable()
, for example
add_library(mypackage mypackage.cpp)
to
add_executable(mypackage mypackage.cpp)
Now we shall modify conanfile.py
to properly build & install the executable:
def package(self): self.copy("*.h", dst="include", src="src") self.copy("*.lib", dst="lib", keep_path=False) self.copy("*.dll", dst="bin", keep_path=False) self.copy("*.dylib*", dst="lib", keep_path=False) self.copy("*.so", dst="lib", keep_path=False) self.copy("*.a", dst="lib", keep_path=False) def package_info(self): self.cpp_info.libs = ["NoxecoDB"]
with
def package(self): self.copy("mypackage", src="bin", dst="bin", keep_path=False) def package_info(self): self.env_info.PATH = os.path.join(self.package_folder, "bin") def deploy(self): self.copy("mypackage", dst="bin", src="bin")
and add
import os.path
to the top of the file
Now let’s add a main()
function to src/mypackage.cpp
. Replace the file’s content with
#include <iostream> int main(int argc, char** argv) { std::cout << "Hello World!" <<std::endl; }
Now it’s time to install the dependencies & build the project using
conan install . && conan build .
The executable will be in
bin/mypackage
You can run it using
./bin/mypackage
which will print
Hello World!
I also recommend to add this .gitignore
:
CMakeCache.txt CMakeFiles/ Makefile bin/ cmake_install.cmake conan.lock conanbuildinfo.cmake conanbuildinfo.txt conaninfo.txt graph_info.json
When running
conan install .
you see ERROR: Missing binary
error messages like this:
Installing (downloading, building) binaries... ERROR: Missing binary: cpr/1.6.2:76fe60a9d5c829a2384b0f578695b5a6357b8acc ERROR: Missing binary: gtest/cci.20210126:c37dc23725d84483088a68c29e2dd7122c328359 ERROR: Missing binary: jsoncpp/1.9.4:718278bac9f92b77a9a44bfbe1aa00d1c8344d51 ERROR: Missing binary: libcurl/7.78.0:d287dc966931230205222ceabf47400733e72fa3 ERROR: Missing binary: openssl/1.1.1l:c3baf9fae083edda2e0c5ef3337b6a111016a898 ERROR: Missing binary: zlib/1.2.11:c3baf9fae083edda2e0c5ef3337b6a111016a898
Use the --build=missing
flag for conan install
to enable building the dependencies for which no binaries are available:
conan install . --build=missing
Configuration: [settings] arch=armv8 arch_build=armv8 build_type=Release compiler=gcc compiler.libcxx=libstdc++ compiler.version=9 os=Linux os_build=Linux [options] [build_requires] [env] openssl/1.1.1l: Not found in local cache, looking in remotes... openssl/1.1.1l: Trying with 'conancenter'... Downloading conanmanifest.txt completed [0.26k] Downloading conanfile.py completed [40.47k] Downloading conan_export.tgz completed [0.25k] Decompressing conan_export.tgz completed [0.00k] openssl/1.1.1l: Downloaded recipe revision 0 cpr/1.6.2: Not found in local cache, looking in remotes... cpr/1.6.2: Trying with 'conancenter'... Downloading conanmanifest.txt completed [0.25k] Downloading conanfile.py completed [9.62k] Downloading conan_export.tgz completed [0.30k] Decompressing conan_export.tgz completed [0.00k] cpr/1.6.2: Downloaded recipe revision 0 WARN: cpr/1.6.2: requirement libcurl/7.80.0 overridden by elasticlient/0.2 to libcurl/7.78.0 libcurl/7.78.0: Not found in local cache, looking in remotes... libcurl/7.78.0: Trying with 'conancenter'... Downloading conanmanifest.txt completed [0.70k] Downloading conanfile.py completed [27.11k] Downloading conan_export.tgz completed [0.23k] Decompressing conan_export.tgz completed [0.00k] libcurl/7.78.0: Downloaded recipe revision 0 jsoncpp/1.9.4: Not found in local cache, looking in remotes... jsoncpp/1.9.4: Trying with 'conancenter'... Downloading conanmanifest.txt completed [0.65k] Downloading conanfile.py completed [4.90k] Downloading conan_export.tgz completed [0.25k] Decompressing conan_export.tgz completed [0.00k] jsoncpp/1.9.4: Downloaded recipe revision 0 gtest/cci.20210126: Not found in local cache, looking in remotes... gtest/cci.20210126: Trying with 'conancenter'... Downloading conanmanifest.txt completed [0.39k] Downloading conanfile.py completed [8.14k] Downloading conan_export.tgz completed [0.32k] Decompressing conan_export.tgz completed [0.00k] gtest/cci.20210126: Downloaded recipe revision 0 conanfile.py (elasticlient/0.2): Installing package Requirements cpr/1.6.2 from 'conancenter' - Downloaded jsoncpp/1.9.4 from 'conancenter' - Downloaded libcurl/7.78.0 from 'conancenter' - Downloaded openssl/1.1.1l from 'conancenter' - Downloaded zlib/1.2.11 from 'conancenter' - Cache Packages cpr/1.6.2:76fe60a9d5c829a2384b0f578695b5a6357b8acc - Missing jsoncpp/1.9.4:718278bac9f92b77a9a44bfbe1aa00d1c8344d51 - Missing libcurl/7.78.0:d287dc966931230205222ceabf47400733e72fa3 - Missing openssl/1.1.1l:c3baf9fae083edda2e0c5ef3337b6a111016a898 - Missing zlib/1.2.11:c3baf9fae083edda2e0c5ef3337b6a111016a898 - Missing Build requirements gtest/cci.20210126 from 'conancenter' - Downloaded Build requirements packages gtest/cci.20210126:c37dc23725d84483088a68c29e2dd7122c328359 - Missing Installing (downloading, building) binaries... ERROR: Missing binary: cpr/1.6.2:76fe60a9d5c829a2384b0f578695b5a6357b8acc ERROR: Missing binary: gtest/cci.20210126:c37dc23725d84483088a68c29e2dd7122c328359 ERROR: Missing binary: jsoncpp/1.9.4:718278bac9f92b77a9a44bfbe1aa00d1c8344d51 ERROR: Missing binary: libcurl/7.78.0:d287dc966931230205222ceabf47400733e72fa3 ERROR: Missing binary: openssl/1.1.1l:c3baf9fae083edda2e0c5ef3337b6a111016a898 ERROR: Missing binary: zlib/1.2.11:c3baf9fae083edda2e0c5ef3337b6a111016a898
Run this command to create a debug
profile from your default
profile:
cp ~/.conan/profiles/default ~/.conan/profiles/debug && sed -i -e 's/Release/Debug/g' ~/.conan/profiles/debug
Example output from conan profile show debug
:
[settings] os=Linux os_build=Linux arch=x86_64 arch_build=x86_64 compiler=gcc compiler.version=9 compiler.libcxx=libstdc++ build_type=Debug [options] [conf] [build_requires] [env]
In order to list local conan
packages, run
conan search
$ conan search Existing package recipes: cpr/1.6.2 elasticlient/0.2 elasticlient/[email protected]/testing gtest/cci.20210126 jsoncpp/1.9.4 libcurl/7.69.1 libcurl/7.78.0 openssl/1.1.1l zlib/1.2.11
When building your conan package, you see this CMake error:
CMake Error at /usr/share/cmake-3.16/Modules/FindPackageHandleStandardArgs.cmake:146 (message): Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR (missing: OPENSSL_CRYPTO_LIBRARY OPENSSL_INCLUDE_DIR) Call Stack (most recent call first): /usr/share/cmake-3.16/Modules/FindPackageHandleStandardArgs.cmake:393 (_FPHSA_FAILURE_MESSAGE) /usr/share/cmake-3.16/Modules/FindOpenSSL.cmake:447 (find_package_handle_standard_args) ../_deps/curl-src/CMakeLists.txt:365 (find_package)
even though your conanfile.py
declares OpenSSL as a dependency:
class MyPackageConan(ConanFile): # ... requires = ("openssl/1.1.1l", )
Make sure that the project’s CMakeLists.txt
contains these lines:
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) conan_basic_setup()
Typically, the way to do this is to use this code which is automatically generated by conan new
:
# This small hack might be useful to guarantee proper /MT /MD linkage # in MSVC if the packaged project doesn't have variables to set it # properly tools.replace_in_file("hello/CMakeLists.txt", "PROJECT(HelloWorld)", '''PROJECT(HelloWorld) include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) conan_basic_setup()''')
in source()
like this:
def source(self): self.run("git clone https://github.com/conan-io/hello.git") # This small hack might be useful to guarantee proper /MT /MD linkage # in MSVC if the packaged project doesn't have variables to set it # properly tools.replace_in_file("hello/CMakeLists.txt", "PROJECT(HelloWorld)", '''PROJECT(HelloWorld) include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) conan_basic_setup()''')
Note that you need to replace both hello/CMakeLists.txt
with the correct filename (typically, just replace hello
by). Also, you need to replace both instances PROJECT(HelloWorld)
by the actual line from your CMakeLists.txt
in order for the replace command to work.
Just add build_requires = ('dep1/version1', 'dep1/version2')
to your conanfile.py
:
class MyPackageConan(ConanFile): # ... requires = ("openssl/1.1.1l", ) build_requires = ("jsoncpp/1.9.4", )
If you want to run git submodule update
in your conanfile.py
, you can simple add a self.run()
command after the git clone command
:
self.run("git clone https://github.com/conan-io/hello.git") self.run("cd hello && git submodule update --init --recursive")
self.run("git clone https://github.com/seznam/elasticlient.git -b version-0.2") self.run("cd elasticlient && git submodule update --init --recursive")
Note that you need to cd <directory> && git submodule update
If you want to create a new conan build recipe for a package that already exists, use
conan new hello/0.1
conan new hello/0.1 -t
More info: See packaging docs
When building a library using conan, this is the default conanfile.py
definition for building using CMake
cmake = CMake(self) cmake.configure(source_folder="hello") cmake.build()
You can easily add definitions like this:
cmake.definitions["MY_FLAG"] = "1"
This will generate -DMY_FLAG=1
when calling CMake
Full example:
cmake = CMake(self) cmake.definitions["USE_SYSTEM_CPR"] = "1 cmake.configure(source_folder="elasticlient")" cmake.build()
Note that you need to add all cmake.definitions
calls before calling cmake.configure()
When trying to configure your CMake project using
find_package(Protobuf REQUIRED)
you see an error message like
CMake Error at /usr/share/cmake-3.16/Modules/FindThreads.cmake:49 (message): FindThreads only works if either C or CXX language is enabled Call Stack (most recent call first): /usr/share/cmake-3.16/Modules/FindProtobuf.cmake:420 (find_package) CMakeLists.txt:7 (find_package) -- Configuring incomplete, errors occurred!
You need to put your
project(MyProject)
line before the
find_package(Protobuf REQUIRED)
line. If you don’t have a project()
line, create one.
Add this to your CMakeLists.txt
:
# # Compile test suite # find_package(Boost COMPONENTS system filesystem unit_test_framework REQUIRED) add_executable(test_myprogram tests/MyTest.cpp ) target_include_directories(test_myprogram PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include") target_compile_features(test_myprogram PRIVATE cxx_std_17) target_link_libraries(test_myprogram ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ) add_test(test_myprogram test_myprogram) # make "make test" run the test program add_custom_target(test DEPENDS myprogram COMMAND ./test_myprogram )
In order to build the program and the test, run
make
In order to run the tests, use
make test
When compiling your CMake-based C++
CMake Error at /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake:117 (find_package): Could not find a package configuration file provided by "boost_unit_test_framework" (requested version 1.71.0) with any of the following names: boost_unit_test_frameworkConfig.cmake boost_unit_test_framework-config.cmake Add the installation prefix of "boost_unit_test_framework" to CMAKE_PREFIX_PATH or set "boost_unit_test_framework_DIR" to a directory containing one of the above files. If "boost_unit_test_framework" provides a separate development package or SDK, be sure it has been installed. Call Stack (most recent call first): /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake:182 (boost_find_component) /usr/share/cmake-3.16/Modules/FindBoost.cmake:443 (find_package) OCCUtils/CMakeLists.txt:58 (find_package) -- Configuring incomplete, errors occurred!
The error message is trying to tell you that you don’t have the boost unit test
library installed (or CMake can’t find it).
On Ubuntu, for example, install it using
sudo apt -y install libboost-test-dev
On Windows you can install it using the prebuilt boost binaries for Windows.