I tries to use FOREACH to generated several pb files. And make two list names PROTO_SRCS & PROTO_HDRS like below.
I can use it in the main CMakeLists. Like add_executable(a SHARED ${PROTO_SRCS} main.cpp).
But I can not use this param in subdirectories to make a library. when I type "cmake .." in main CMakelists build dir. It shown that "Cannot find source file: a.pb.cc".
main CMakeLists.txt
add_library(xxx SHARED ${PROTO_SRCS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/back back)
in src/back CMakeLists.txt
add_executable(yyy ${PROTO_SRCS})
and I can use message to show ${PROTO_SRCS} in subdir so it pass into successfully.
Please help me to point out the problem. Thx a lot
The issue is that in CMake versions older than 3.20 the GENERATED property of source files is only visible in the directory where it is set. Thus, when you add the protobuf-generated source files to a target defined in a different directory, CMake will no longer know that these are files generated during the build. Consequently, CMake will try to locate these files at configuration time, when they obviously do not exist yet.
Unfortunately, at the time of writing there is only a release candidate for CMake 3.20 and no official release yet. So depending on whether you need to coordinate with other coworkers or whether you're working on this project on your own it might not be feasible to use the release candidate.
If you can't use it, the alternative is to create an object library via add_library(protobuf_objs OBJECT ${PROTO_SRCS}) in the directory where you generate the files and to use target_sources(xxx PRIVATE $<TARGET_OBJECTS:protobuf_objs>) and target_sources(yyy PRIVATE $<TARGET_OBJECTS:protobuf_objs>) instead of adding the ${PROTO_SRCS} as source files to these targets directly.
I have recently installed CMake in order to write code to make use of Libbitcoin in C++ but I am having a hard time, I was trying to build the example code on GitHub here. And it haters been going terribly. I can't manage to link the library right in CMake, here is my code. I read and people were saying that I should try Autoconf but I have no idea how to even start that as I know nothing about Autoconf. I have CMake 3.16, and installed Libbitcoin with brew but alias were made in /usr/local/include for the library, I am on Mac OS X 10.15. The CMake runs fine but when running "make", it responds with:
Scanning dependencies of target CreateAddr
main.cxx:1:10: fatal error: bitcoin/bitcoin.hpp: No such file or directory
1 | #include <bitcoin/bitcoin.hpp>
| ^~~~~~~~~~~~~~~~~~~~~
Here is my CMake text:
Please all help is appreciated I am beyond lost.
It is hard to be sure without knowing the specifics of your installation, but it appears that your include directory paths may be overlapping with what is specified for the header in main.cxx. The include_directories() call tells the compiler to include headers from this directory:
/usr/local/include/bitcoin
Then, in main.cxx, you're including the file with bitcoin/bitcoin.hpp. Combining these suggests the file is located here:
/usr/local/include/bitcoin/bitcoin/bitcoin.hpp
The error states the header could not be found, so perhaps you meant to locate it here:
/usr/local/include/bitcoin/bitcoin.hpp
In that case, just remove the relative directory path from the main.cxx file, like this:
#include <bitcoin.hpp>
Also, you want to link to your libbitcoin library correctly. Using link_directories() is not recommended. Instead, you can specify the full path to your libbitcoin library directly in the call to target_link_libraries(). The library may not be located in /usr/local/include/bitcoin. With these changes, the last few lines in your CMake would look something more like this:
include_directories(/usr/local/include/bitcoin)
add_executable(CreateAddr main.cxx)
target_link_libraries(CreateAddr PUBLIC /your/path/to/libs/libbitcoin.so)
I've I'm trying to build this "Hello World" wxWidgets example on Linux, using the following cmake script:
cmake_minimum_required (VERSION 2.6)
project (wxL)
find_package(wxWidgets 3.0.0 REQUIRED
COMPONENTS base core net xml html adv qa richtext
)
file(GLOB SOURCES "src/*.cpp")
add_executable(wxL ${SOURCES})
Building the project yields this error:
src/wxL.cpp:3:10: fatal error: wx/wxprec.h: No such file or directory
The file specified in the include, wx/wxprec.h can be found on disk at this location:
/usr/include/wx-3.0/wx/wxprec.h
Furthermore, another program that I have built from source includes the same file (also using cmake) and builds just fine.
So, how do I use cmake to tell the compiler that the file should be included from somewhere in the system directories?
I know I'm missing something basic, but I can't figure out what.
Although you've found the package, your executable does not know anything about it.
For the executable to compile correctly, it needs to find header files for your package together with the .so / .a files. Following example should get you started:
include_directories(${wxWidgets_INCLUDE_DIRS})
add_executable(wxL <add-source-files-here>)
target_link_libraries(wxL ${wxWidgets_LIBRARIES}) // links wxWidgets libraries to your executable
Please note that using glob is not a recommended way of adding source files to your project.
Background
I'm a complete newb with C++ and I've been running into one headache after another, so forgive me if this is incredibly simple and I'm just that dumb...
I have a project that should ultimately compile and run in Linux. Unfortunately after lots of issues with my C++ development environemnt (still unresolved), I gave up on trying to develop in Linux and moved to Windows Visual Studio 2017. My hope was to get my code working in Windows and then, since C++ is supposedly a portable language, it should just work in Linux with minimal changes.
For a day or so Visual Studio seemed to be working. I could write code, hit "compile", and like magic it would run. I threw together a few classes to construct a directed acyclic graph, used the standard library for a hash table, and then I tried to create a socket...
Windows and Linux use different libraries for sockets (<sys/socket.h> vs <winsock.h>) so I needed some way to abstract the differences, and I preferred a well-established standard. Googling around I found the Boost library that seemed to fit my needs... That's when everything went to hell.
My project setup
Because this project will be developed across a variety of platforms and IDEs (some people use Windows + Visual Studio, some people use Mac + Eclipse, and others use Linux + VIM) I opted to make it a CMake project. After several hours of reading and learning and research it seems like CMake should give me what I want (convenient and reproducible cross-platform builds with little or no dependency issues)
My source code (directly from the Boost Getting Started on Windows guide) is as follows:
CMakeProject2.cpp
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
using namespace boost::lambda;
typedef std::istream_iterator<int> in;
std::for_each(
in(std::cin), in(), std::cout << (_1 * 3) << " ");
}
Per the Boost Getting Started on Windows guide, I downloaded Boost from here:
https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0.zip
(interestingly, the Getting Started guide is titled "Boost Getting Started on Windows - 1.69.0", yet it linked to Boost versions 1.67.0)
After downloading and extracting the ZIP file, I had a whole mess of files - but no idea where to put them:
Attempts to Get It Working So Far
I tried to add the Boost library to my project, but none of the expected menu options were available:
Although I couldn't find a single page that warns you of this gotcha, apparently CMake projects don't have the elusive "Properties" window - and instead third party libraries must somehow be included via the CMakeLists.txt file
For starters, I copied the entire 540 MB contents of the Boost ZIP file to within my project under the folder name "Boost":
I then tried a series of different CMakeList.txt commands:
Per How do you add Boost libraries in CMakeLists.txt?:
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost REQUIRED COMPONENTS lambda)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
add_executable(CMakeProject2 "CMakeProject2.cpp" "CMakeProject2.h")
target_link_libraries(CMakeProject2 ${Boost_LIBRARIES})
endif()
Per https://www.selectiveintellect.net/blog/2016/7/29/using-cmake-to-add-third-party-libraries-to-your-project-1:
include("Boost")
add_subdirectory("Boost")
add_subdirectory("boost")
add_subdirectory("Boost/boost")
add_subdirectory("Boost/boost/lambda")
target_link_libraries(boost)
target_link_libraries(Boost)
Per https://cmake.org/pipermail/cmake/2009-November/033249.html:
SET (Boost_FIND_REQUIRED TRUE)
SET (Boost_FIND_QUIETLY TRUE)
SET (Boost_DEBUG FALSE)
set (Boost_USE_MULTITHREADED TRUE)
set (Boost_USE_STATIC_LIBS TRUE)
SET (Boost_ADDITIONAL_VERSIONS "1.67" "1.67.0")
FIND_PACKAGE(Boost COMPONENTS lambda)
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
I tried several other incantations (not being familiar with C++ or CMake as a tool) and either received errors from CMakeLists.txt, or from CMakeProject2.cpp about cannot open source file "boost/lambda/lambda.hpp". In fact, with regards to those "CMakeLists.txt" errors, after adding enough lines to my file I started to crash Visual Studio regularly. Note that I have an 8th generation i7, 32 gigabytes of RAM, and an M.2 NVMe hard drive -- so I was rather impressed that a few lines in a text file pissed off Microsoft enough to lock up my computer for 10 minutes at a time.
Failing all of that, I tried copying the files I needed directly into my project:
Now, again, I'm new to C/C++ development and everything that can go wrong has gone wrong. So far I've spent almost two weeks and barely managed to compile a single "Hello, World" app across two computers, three IDEs, and four compilers. I've yet to have any success including a third party library, from anywhere, of any popularity level or simplicity level, and actually compile a functioning program that references the library. So believe me when I say: I don't know the difference between a "header-only library" and... whatever the alternative is. I just know that, according to the Boost Getting Started on Windows guide, most of Boost is "headers only" and therefore I shouldn't have any build step -- it should be simple to use it. Furthermore, this example (using boost::lambda) is - per their instructions - a header-only library, and should therefore be extremely easy to use.
I now updated the source code slightly to look in the current directory, instead of looking in the system include directory (which, as far as I'm aware at this point, doesn't exist in Windows):
#include "boost/lambda/lambda.hpp"
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
using namespace boost::lambda;
typedef std::istream_iterator<int> in;
std::for_each(
in(std::cin), in(), std::cout << (_1 * 3) << " ");
}
Now I can manually verify that this file exists (the file CMakeProject2\CMakeProject2\boost\lambda\lambda.hpp can be found in File Explorer) - yet I'm still getting errors:
cannot open source file "boost/lambda/lambda.hpp"
Some further Googling led me to update my CMakeLists.txt file once more, putting it in its current form:
# CMakeList.txt : CMake project for CMakeProject2, include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.8)
# Add source to this project's executable.
file(GLOB CMakeProject2_SRC
"*.h"
"*.cpp"
"**/*.h"
"**/*.cpp"
"**/*.hpp"
"boost/lambda/lambda.hpp"
)
add_executable (CMakeProject2 ${CMakeProject2_SRC})
#add_executable (CMakeProject2 "CMakeProject2.cpp" "CMakeProject2.h")
# TODO: Add tests and install targets if needed.
Despite this I'm still getting the error:
cannot open source file "boost/lambda/lambda.hpp"
At this point I'm ripping my hair out. What am I doing wrong? What do I not know? How is something as simple as the Boost-equivalent of "Hello, World" not working for me?
Following recipe should work
Download Boost binaries from official boost binaries location and install to say C:\Boost
Most times you do not need to build Boost on your own.
Your CMakeLists.txt should look like follows
cmake_minimum_required (VERSION 3.8)
project(boostAndCMake)
set(BOOST_ROOT "C:\Boost") # either set it here or from the command line
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost REQUIRED COMPONENTS system) # header only libraries must not be added here
add_executable(CMakeProject2 CMakeProject2.cpp CMakeProject2.h)
target_include_directories(CMakeProject2 PUBLIC ${Boost_INCLUDE_DIRS})
target_link_libraries(CMakeProject2 ${Boost_LIBRARIES})
Because we used REQUIRED on the find_package call, CMake will fail execution and skip the rest of the script if it cannot be found. So no need to check Boost_FOUND. You need to check it, when you omit REQUIRED.
Now from the command line call from the directory where your script resides:
cmake -H. -Bbuildit -G "Visual Studio 15 2017" -DBOOST_ROOT=C:\Boost
This creates a build directory named buildit in the current directory, further creates a solution for Visual Studio 2017 inside the build directory and provides the setting for the variable BOOST_ROOT that is used in the find_package call to identify the Boost directory on your computer. To see what options are available on the find_package(Boost ...) call see FindBoost documentation in CMake.
Header Only Libraries
If your libraries are header only you need to omit them from the find_package(Boost ...) call. To see which libraries are not header only see this post.
Using newer Boost versions
If your CMake installation cannot find the requested version, e.g. 1.69.0, but supports the naming scheme of the more recent Boost version you can use it with set(Boost_ADDITIONAL_VERSIONS "1.69.0" "1.69"). Last change of the Boost naming scheme was from 1.65.1 to 1.66.
Here's a working setup for Boost 1.68 with CMake 3.12. Boost 1.69 is apparently "too new" for cmake to detect it properly. Since boost is not buildable by cmake, cmake itself must provide a FindBoost.cmake module that must keep up with boost changes.
So anyway, the CMakeLists.txt is as small as this:
cmake_minimum_required(VERSION 3.11)
project(foobar)
find_package(Boost 1.68 REQUIRED)
add_executable(foo foo.cpp)
target_link_libraries(foo PUBLIC Boost::boost)
Of course, you can split it in many subdirectories.
Invoking CMake in the command line should look like this:
cmake -DCMAKE_PREFIX_PATH=path_to_local_directory ..
Where path_to_local_directory is the installation path of all library you want to depend on. It will work for Boost, nlohmann_json, glfw3, Qt, you name it *(1). For my case, it was C:/local/ and another case was ../external/ (yes, it can be a directory local to the project!)
Let's take a peek at my own C:/local/:
ls -l /c/local/
total 12
drwxr-xr-x 1 myself 197609 0 May 26 2018 boost_1_67_0/
drwxr-xr-x 1 myself 197609 0 Sep 5 02:02 boost_1_68_0/
WARNING: Ensure your compiler architecture is the same as the installed boost version. Or else cmake will simply not find it.
I think that about it. The next CMake version (3.14) should work with the latest boost.
*(1) The said library will either need to export it's CMake target or you must provide a FindXXX.cmake
I'm using CMake 3.22 with Boost version 1.78.
The simplest solution is to set the Boost_INCLUDE_DIR when calling Cmake:
cmake -DBoost_INCLUDE_DIR=boost
Pass the directory to where the Boost libraries are. If you're using Visual Studio you can also set this in your CMake Settings:
Or, in the CMakeSettings.json file:
"cmakeCommandArgs": "-DBoost_INCLUDE_DIR=boost",
In my opinion, this is better than using the set function because you're not hard coding the path.
Add a target_include_directories(CMakeProject2 PRIVATE .) into your CMakeList.txt.
The . is the relative path of boost/lambda/lambda.hpp from CMakeLists.txt
And you should not add any .hpp file to the source list.
I added the xgboost library as a git submodule of my project and I'm trying to add it to cmake as a subdirectory. Unfortunately it's not working. A simple hello world project with the following CMakeLists.txt replicates the error that I'm getting.
cmake_minimum_required(VERSION 3.2)
project(foo)
add_subdirectory(xgboost)
add_executable(${PROJECT_NAME} foo.cpp)
target_link_libraries(${PROJECT_NAME} xgboost)
After building the library there is nothing in the xgboost/lib directory so I get the following error.
clang: error: no such file or directory:
'/Users/.../myproject/xgboost/lib/libxgboost.dylib'
I think that the problem is generated in their CMakeLists file since they have two different targets. Maybe cmake is choosing the wrong target but I'm not familiar enough with cmake to figure it out. The following code is from xgboost's CMakeLists.
# Executable
add_executable(runxgboost $<TARGET_OBJECTS:objxgboost> src/cli_main.cc)
set_target_properties(runxgboost PROPERTIES
OUTPUT_NAME xgboost
)
set_output_directory(runxgboost ${PROJECT_SOURCE_DIR})
target_link_libraries(runxgboost ${LINK_LIBRARIES})
# Shared library
add_library(xgboost SHARED $<TARGET_OBJECTS:objxgboost>)
target_link_libraries(xgboost ${LINK_LIBRARIES})
set_output_directory(xgboost ${PROJECT_SOURCE_DIR}/lib)
#Ensure these two targets do not build simultaneously, as they produce outputs with conflicting names
add_dependencies(xgboost runxgboost)
My questions in order of importance are:
Is there any way to fix it without modifying xgboost's CMakeLists.txt file?
Is it reasonable to try to add xgboost to my project as a git submodule?
Is there any reason cmake is not instructing to build the library?
Note: There were several edits to this question since I tried to narrow down the problem and to provide more information.
(I would love to ask for few things beforehand in the comment section, but I have too low reputation to do so, so I will just give it a shot ;))
I have few suspects, and one of them is ${CMAKE_SOURCE_DIR} of the submodule's root CMakeLists.txt. Although the paths are set properly when you run that CMakeLists.txt alone, cmake gets confused the moment you add it as your subdirectory. Have you looked into another directories for your output binaries?
First I would suggest testing this hypothesis, and then I would suggest writing similar, but separate CMakeLists.txt file for xgboost library, and then substitute it in the project temporarily. Unfortunately the CMakeLists.txt filename is hardcoded and there is no possibility to have two files of that kind in one directory; so it seems that the answer to 1) is, that you rather have to change the file.
For the 2): as long as it does not require huge additional logic in your CMakeLists.txt, it makes sense. Other viable option is to create an install target, which you can use to install your xgboost library locally (using CMAKE_INSTALL_PREFIX(doc) variable), and then add the installation path to your CMAKE_LIBRARY_PATH(doc).