CMake Error: "add_subdirectory not given a binary directory" - c++

I am trying to integrate Google Test into the subproject of bigger project and I cannot find the solution that would be satisfying for me.
I have two constraints:
the source code of Google Test is already somewhere in the project structure (thus using URL to download it from git repository is not an option)
the source code of Google Test is not a subdirectory of my subproject (and never will)
So when I tried to do something like this:
add_subdirectory( ${GOOGLETEST_PROJECT_LOCATION})
I received:
CMake Error at unit_tests/CMakeLists.txt:10 (add_subdirectory):
add_subdirectory not given a binary directory but the given source
directory "${GOOGLETEST_PROJECT_LOCATION}" is not a subdirectory of
"${UNIT_TEST_DIRECTORY}". When
specifying an out-of-tree source a binary directory must be explicitly
specified.
On the other hand maybe ExternalProject_Add could be a solution but I do not know how shall I use it when I do not want to download sources at all and use sources from specific location in the project.
Project structure looks more or like like this:
3rdparty
|--googletest
...
subproject
|--module1
|--file1.cpp
|--CMakeLists.txt
|--module2
|--file2.cpp
|--CMakeLists.txt
|--include
|--module1
|--file1.h
|--module2
|--file2.h
|--unit_test
|--module1
|--file1test.cpp
|--module2
|--file2test.cpp
|--CMakeLists.txt
|--CMakeLists.txt
CMakeLists.txt

The error message is clear - you should also specify build directory for googletest.
# This will build googletest under build/ subdirectory in the project's build tree
add_subdirectory( ${GOOGLETEST_PROJECT_LOCATION} build)
When you give relative path (as a source directory) to add_subdirectory call, CMake automatically uses the same relative path for the build directory.
But in case of absolute source path (and when this path isn't in your source tree), CMake cannot guess build directory, and you need to provide it explicitly:
See also documentation for add_subdirectory command.

I feel obligated to comment on this because this was the top search result when I was googling this error.
For me, I'm apparently an idiot: I had modified the CMakeLists.txt file in the src directory of my project, but I didn't realize the file was locked and VS Code wasn't actually saving even when I hit Ctrl+S. Check the file tab in VS Code and see if there's a white dot there, indicating the file isn't saved. Hit Ctrl+S and see if you get a pop-up in the lower-right corner prompting you to try again as superuser.
I've still got errors, but they're new errors that make sense for my project.

Related

correspondence between muti cmakelists.txt file and vs project structure that created by cmake vs geneator?

I'm trying to build a visual studio c++ project under windows by cmake, there are two cmakelists.txt file in my source, and they are't parent-child relationship, main cmakelists.txt link library and add executable, the other one is only responsible for collating the dependent path to the global variable and passing to main cmakelists.txt file use.
At the beginning of executing cmake script, i pass the build dir path by command line parameter "-B".
Final i got the output file, but the structure of result direcotry puzzled me.Main-cmakelists.txt generate configuration file to build folder that was specified by earlier. But the other one cmakelists.txt, which generate configuration file outside, and one level heigher than specified build folder, and the folder with same name as the folder where sub-cmakelists.txt located.
I tried to find answer in offical documents and book like cmakecookbook, currently, no relevant entry found.
How can i specify the path for the generator ouput of sub-cmakelists.txt? I want to unify same build root folder for all cmakelists.
Is there have some professional tutorial introduction about correspondence between cmake file and vs project file?
Thanks.
enter image description here
The second parameter of add_subdirectory() command, can specify the binary_dir path to place the output file for sub-cmakelist.

CMake with 3rd party libraries that need to be built along with the project

I am confused on the right way to get an external library integrated into my own Cmake project (This external project needs to be built along with my project, it's not installed separately, so we can't use find_library, or so I think)
Let's assume we have a project structure like this (simplified for this post):
my_proj/
--CMakeLists.txt
--src/
+---CMakeLists.txt
+---my_server.cpp
That is, we have a master CMakeLists.txt that basically sits at root and invokes CMakeLists for sub directories. Obviously, in this example, because its simplified, I'm not showing all the other files/directories.
I now want to include another C++ GitHub project in my build, which happens to be this C++ bycrypt implementation: https://github.com/trusch/libbcrypt
My goal:
While building my_server.cpp via its make process, I'd like to include the header files for bcrypt and link with its library.
What I've done so far:
- I added a git module for this external library at my project root:
[submodule "third_party/bcrypt"]
path = third_party/bcrypt
url = https://github.com/trusch/libbcrypt
So now, when I checkout my project and do a submodule update, it pulls down bcrypt to ${PROJ_ROOT}/third_party
Next up, I added this to my ROOT CMakeLists.txt
# Process subdirectories
add_subdirectory(third_party/bcrypt)
add_subdirectory(src/)
Great. I know see when I invoke cmake from root, it builds bcrypt inside third_party. And then it builds my src/ directory. The reason I do this is I assume this is the best way to make sure the bcrypt library is ready before my src directory is built.
Questions:
a) Now how do I correctly get the include header path and the library location of this built library into the CMakeLists.txt file inside src/ ? Should I be hardcoding #include "../third_party/bcrypt/include/bcrypt/bcrypt.h" into my_server.cpp and -L ../third_party/libcrypt.so into src/CMakeLists.txt or is there a better way? This is what I've done today and it works, but it looks odd
I have, in src/CMakeLists.txt
set(BCRYPT_LIB,"../third_party/bcrypt/libbcrypt.so")
target_link_libraries(my app ${MY_OTHERLIBS} ${BCRYPT_LIB})
b) Is my approach of relying on sequence of add_directory correct?
Thank you.
The best approach depends on what the bcrypt CMake files are providing you, but it sounds like you want to use find_package, rather than hard-coding the paths. Check out this answer, but there are a few different configurations for find_package: MODULE and CONFIG mode.
If bcrypt builds, and one of the following files gets created for you:
FindBcrypt.cmake
bcrypt-config.cmake
BcryptConfig.cmake
that might give you an idea for which find_package configuration to use. I suggest you check out the documentation for find_package, and look closely at how the search procedure is set up to determine how CMake is searching for bcrypt.

CMake install (TARGETS in subdirectories)

Consider the following CMakeLists.txt file:
add_subdirectory(execA)
add_subdirectory(libB)
install(TARGETS execA libB
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
I get the following error:
install TARGETS given target "execA" which does not exist in this
directory
execA and libB have their own CMakeList.txt files and are located under project directory, as well as the build directory I'm running cmake (cmake ..):
project
|------ CMakeList.txt (the one with the code)
|----execA
| \- .cpp, .hpp and CMakelist.txt
|----libB
| \- .cpp, .hpp and CMakelist.txt
|---- lib
|---- bin
\---- build (where I´m commanding: $ cmake ..
How do I fix this error?
According to this bugreport, install(TARGETS) command flow accepts only targets created within the same directory.
So you need either move the add_library() call into the top-level directory, or split install(TARGETS) call into per-target ones, and move each of them into the corresponding subdirectory.
Since CMake 3.13 install(TARGETS) can work even with targets created in other directories.
install(TARGETS) can install targets that were created in other directories. When using such cross-directory install rules, running make install (or similar) from a subdirectory will not guarantee that targets from other directories are up-to-date.
Even though it would help seeing the CMakeLists.txt files contained in the subdirectories, I guess they contain add_executable and/or add_library statements to create your stuff.
Also, because of your example, I guess you are using the same name of your directories for your targets.
That said, you should know that symbols defined in a CMakeLists.txt file in a subdirectory are not visible by default within the context of the CMakeLists.txt file in the parent directory. Because of that, you should rather move your install statements within the CMakeLists.txt files within your subdirectories.
This should solve the problem, if my thoughts were right. Otherwise, I strongly suggest you to post in your question also the content of the other files above mentioned.
Anyway, the error is quite clear.
The file that contains the install statement for the target named X does not contain a target creation statement (add_executable and the others) that gives birth to that target, so it goes on saying that that target does not exist in that directory.
This still seems to be a pain point in CMake 3.11.
In our codebase, we have many targets defined in subdirectories and need to create an assortment of installers with different configurations and (potentially overlapping) combinations of targets.
Here's my solution:
Before calling add_subdirectory in your root CMakeLists.txt file, create a GLOBAL property with the names of the target(s) you want to include in your installer.
Wrap target creation functions (add_executable, etc.) in your own custom functions. Within those functions check if the target is present in the global property, and invoke install accordingly.
That approach allows you to centralize installer configuration.
Also: To support creation of multiple installers, we populate our global list along with other installer properties in separate .cmake files. When we invoke cmake, we pass the name of the installer configuration CMake file as a command-line argument. Our root CMakeLists.txt file simply calls include with that file.

cmake - CMakeLists.txt is not in root folder (but is included in source)

I'm trying to compile a libpng library. The thing is that I need a specific version of this library - 1.2.37 - because the project I'm using it in is written with this version.
I've found the source code of this version here (GnuWin32 project).
But the folder structure looks something like this:
libpng-1.2.37-src/
contrib/
projects/
scripts/
CMakeLists.txt
png.h
pngread.c
pngwrite.c
...
See, the CMakeLists.txt is one level deeper than the source files.
I've tried:
source directory libpng-1.2.37-src/ -> resulted in error: The source directory does not appear to contain CMakeLists.txt
source directory libpng-1.2.37-src/scripts -> resulted in multiple errors: File libpng-1.2.37-src/scripts/scripts/libpng.pc.in does not exist.
copy CMakeLists.txt from /scripts to /libpng-1.2.37-src and set source directory to /libpng-1.2.37-src -> resulted in error: The source "/libpng-1.2.37-src/CMakeLists.txt" does not match the source "/libpng-1.2.37-src/scripts/CMakeLists.txt" used to generate cache.
What should I do to make it work? I don't know why the CMakeLists.txt file would be included if it can't be used.
The INSTALL file explicitely says:
If you want to use "cmake" (see www.cmake.org), copy CMakeLists.txt
from the "scripts" directory to this directory and type
cmake . [-DPNG_MMX=YES] -DCMAKE_INSTALL_PREFIX=/path
make
make install
And as a side note, before this it says that the classic way to install it is:
On Unix/Linux and similar systems, you can simply type
./configure [--prefix=/path]
make check
make install
It sounds like you did right with 3), however you forgot to cleanup the build dir before trying again.
If it's library which you use in your project you can build it automatically via technique called 'superbuild' (use ExternalProject_Add).
By specifying SOURCE_SUBDIR as is described here to subdirectory with CMakeLists.txt you can do something like this
ExternalProject_Add(libpng
GIT_REPOSITORY url-to-your-repository.git
GIT_TAG v1.2.37
SOURCE_SUBDIR "scripts"

CMake Difference between include_directories and add_subdirectory?

I'm learning CMake for building C++ code, and struggling with the following concept. On my root level directory I have some cpp files and a CMakeLists.txt that succesfully generates some thrift code in a gen-cpp directory. My root level CMakeLists.txt contains :
include_directories("path-to-root"/gen-cpp). (along with the relevant thrift auto-generating and includes.
Everything compiles ok but I get run time dynamic library linked errors for undefined symbol referencing a class defined in the gen-cpp directory. When I move the files in the directory to the root level, it runs fine. what am I missing? (I had also adjusted the #include in the root level cpp directorie s to point to "path-to-root"/gen-cpp).
Is this a misunderstanding of using include_directory, where I should be using add_subdirectory. If the latter, would the code in gen-cpp needs its own CMakeLists.txt? Why is this additional file not needed, when the contents of said directory are root level?
add_subdirectory(source_dir): Used to add a subdirectory to the build. There is also a CMakeLists.txt file in the source_dir. This CMakeLists.txt file in the specified source directory will be processed immediately by CMake before processing in the current input file continues beyond this command.
include_directories(dir): Add the given directories to those the compiler uses to search for include files. These directories are added to the directory property INCLUDE_DIRECTORIES for the current CMakeLists file.
The include_directories() is used for adding headers search paths (-I flag) and add_subdirectory() will make no difference in this case.
I suppose, you need to list *.cpp files from gen-cpp folder in add_executable() or add_library() calls, in which you wish these symbols to be.
Alternatively, you can compile all thrift sources into the library and link it with your code.