Why does cmake create a 'source' directory in my build directory? - linux

I am getting kind of frustrated with cmake, as I am trying to learn it and use it properly.
Here is my setup:
I have a directory called ~/project. In this directory, I have:
build directory
source directory
includes directory.
CMakeLists.txt file.
The contents of this CMakeLists.txt file is:
cmake_minimum_required(VERSION 2.8)
project(myProject)
subdirs(source)
I also have another CMakeLists.txt in ~/project/source, and its content is:
cmake_minimum_required(VERSION 2.8)
include_directories("~/project/includes")
add_executable(exec entry.cpp)
Now, I go into the build directory which is empty, and do cmake ... This works fine. However I then see a 'source' directory get created as shown here.
Why is this being created? I do not know what is going on. As I understand it, it should not be doing this, it should give me everything I see here, except for the 'source' directory.
Thanks.

Inside your build directory, CMake re-creates the whole directory structure of your project. The rational is, to keep the project structure. Image a bigger project with several levels of subfolders and sources, libraries and tests scattered in a meaningful way. To run a test, you follow the structure where the test's source is located, just in the build directory instead of the source directory.
As your project, at least as far as CMake knows it, is only the source subdirectory, only this folder is created.
If you really have just the source project, I am not sure whether would be better to place the CMake project just inside source.

Related

CMake cannot find source file, but file was not specified in CMakeLists.txt, in TFS build definition

I'm porting a large project to linux. I wrote all the CMakeLists.txt files, and everything compiles in my machine.
For whatever reason we still use TFS. The old version, not git with TFS.
I'm working in my own branch, but that branch has no build definition for linux. Before I check in, I want to be sure that everything compiles on the server too. So I need to merge my branch to another one, and submit that shelve set to the build job.
In my machine everything compiles fine. But when I run the build in the server, applying a shelveset to the branch that has a linux build definition, I get an error from the build, saying
CMake Error at
/myproject/subproject/CMakeLists.txt:165 (add_library):
Cannot find source file:
/myproject/subproject/IInternalTransactionManager.h
Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
.hpp .hxx .in .txx
Indeed, that file is not there. Cmake complains about the file not being in the sources directory, which is true, because it is in another directory. But the fact is that I'm not asking for it either! My CMakeFiles.txt file does not include that file. That file is a header which is used in a few files, contains only classes definitions (no implementations), and the directory in which myHeader.h resides has been defined in include_directories. My CMakeLists.txt looks something like this:
set(PROJECT_NAME project)
project(${PROJECT_NAME})
include_directories(
../_include
)
set(source_files
main.cpp
file_that_includes_myHeader.cpp
)
add_library( ${PROJECT_NAME} STATIC ${source_files} )
and my file structure is something like:
/myproject/subproject/main.cpp
/myproject/subproject/file_that_includes_myHeader.cpp
/myproject/subproject/CMakeLists.txt
/myproject/_include/myHeader.h
So, why should cmake complaining about a missing file, if such file is not included in the CMakeLists.txt file? And why would this happen only the build in TFS? My guess is that there is something wrong when applying the shelvetset and is not related to my code, but I cannot prove it.
I compared the code after the shelveset is applyied, and still in that version the CMakeLists.txt does not mention myHeader.h
Or, there is some rule about including headers in CMakeLists.txt files which I'm not aware of.
So, after expending too much debuging I contacted the team in charge of the build process. And as it turns out, the building process in the TFS building definition was definetly NOT what I expected. And of course this was not documented.
Our development is mostly in windows (by far). The linux build has a step before building: a script is launched which parses each Visual Studio project file, gets the included files, and substitutes the source files in the CMakeLists.txt files with the one parsed from VS. Right or wrong, is just the way it is.
I could build the linux build in my local machine because everything was done correctly. The windows build worked too, even though the VS project files sometimes included some files which were not in the source directory but in some header only directory, and somehow that compiled. I guess because the directory was defined in the include directory. But When the CMakeLists.txt files were updated, cmake complained (rightly so) about not finding the files.
So, if anybody experiences similar issues, contact your devops team or whoever is in charge of such things.

Finding my Linux shared libraries at runtime

I'm porting an SDK written in C++ from Windows to Linux. There are other binaries, but at its simplest, our SDK is this:
core.dll - implicitly loaded DLL ("libcore.so" shared library on Linux)
tests.exe - an app use to test the DLL (uses google test)
All of my binaries must live in one folder somewhere that apps can find. I've achieved that on Windows. I wanted to achieve the same thing in Linux. I'm failing miserably
To illustrate, Here's the basic project tree. We use CMake. After I build I've got
mysdk
|---CMakeLists.txt (has add_subdirectory() statements for "tests" and "core")
|---/tests (source code + CMakeLists.txt)
|---/core (source code + CMakeLists.txt)
|---/build (all build ouput, CMake output, etc)
|---tests (build output)
|---core (build output)
The goal is to "flatten" the "build" tree and put all the binary outputs of tests, core, etc into one folder.
I tried adding CMake's "install" command, to each of my CMakeLists.txt files (e.g. install(TARGETS core DESTINATION bin). I then then executed sudo make install after my normal build. This put all my binaries in /usr/local/bin with no errors. But when I ran tests from there, it failed to find libcore.so, even though it was sitting right there in the same folder
tests: error while loading shared libraries: libcore.so: Cannot open shared object file: No such file or directory
I read up on the LD_LIBRARY_PATH environment variable and so tried adding that folder (/usr/local/bin) into it and running. I can see I've properly altered LD_LIBRARY_PATH but it still doesn't work. "tests" still can't find libcore.so. I even tried changing the PATH environment variable as well. Same result.
In frustration, I tried brute-force copying the output binaries to a temporary subfolder (of /mysdk/build) and running tests from there. To my surprise it ran.
Then I realized why: Instead of loading the local copy of libcore.so it had loaded the one from the build output folder (as if the full path were "baked in" to the app at build time). Subsequently deleting that build-output copy of libcore.so made "tests" fail altogether as before, instead of loading the local copy. So maybe the path really was baked in.
I'm at a loss. I've read the CMake tutorial and reference. It makes this sound so easy. Aside from the obvious (What am I doing wrong?) I would appreciate if anyone could answer any of the following questions:
What is the correct way to control where my app looks for my shared libraries?
Is there a relationship between my project build structure and how my binaries must then appear when installed?
Am I even close to the right way of doing this?
Is it possible I've somehow inadvertently "baked" (into my app) full paths to my shared libraries? Is that a thing? I use all CMAKE variables in my CMakeLists files.
You can run ldd file to print the shared object dependencies for file. It will tell you where are its dependencies being read from.
You can export the environment variable LD_LIBRARY_PATH with the paths you want the linker to look for. If a dependency is not found, try adding the path where that dependency is located at to LD_LIBRARY_PATH and then run ldd again (make sure you export the variable).
Also, make sure the dependencies have the right permissions.
Updating LD_LIBRARY_PATH is an option. Another option is using RPATH. Please check the example.
https://github.com/mustafagonul/cmake-examples/blob/master/005-executable-with-shared-library/CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
# Project
project(005-executable-with-shared-library)
# Directories
set(example_BIN_DIR bin)
set(example_INC_DIR include)
set(example_LIB_DIR lib)
set(example_SRC_DIR src)
# Library files
set(library_SOURCES ${example_SRC_DIR}/library.cpp)
set(library_HEADERS ${example_INC_DIR}/library.h)
set(executable_SOURCES ${example_SRC_DIR}/main.cpp)
# Setting RPATH
# See https://cmake.org/Wiki/CMake_RPATH_handling
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${example_LIB_DIR})
# Add library to project
add_library(library SHARED ${library_SOURCES})
# Include directories
target_include_directories(library PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/${example_INC_DIR})
# Add executable to project
add_executable(executable ${executable_SOURCES})
# Linking
target_link_libraries(executable PRIVATE library)
# Install
install(TARGETS executable DESTINATION ${example_BIN_DIR})
install(TARGETS library DESTINATION ${example_LIB_DIR})
install(FILES ${library_HEADERS} DESTINATION ${example_INC_DIR})

no such file or directory (cygwin)

I am trying to install a solver (SCIP) with cygwin. After unpacking the folder consists of another 5 folders. The manual says I have to go in folder A and use make. Here, I get the message that one file was not found:
zimpl/bool.h: No such file or directory
This file is in folder B in the path zimpl/src/bool.h. How can I link this file from folder B that cygwin can use it while using make in folder A?
The support says:
Blockquote The error you postet looks like your zimpl softlink is incorrect. If you use a relative path, make sure that it is relative to the position where
the link is created. Most softlinks are created directly in the lib
directory, the zimpl softlink, however, is in a subdirectory of the lib
directory, so you have to go up two directories to get to the main SCIP
directory.
However I am not sure how to check the softlinks.
Thanks!

Building relative to src/ directory with SCons

I have an app with the following (I would have thought quite common) directory hierarchy:
/src
subdir1/ # Subdirs with more source files.
more.c
SConscript
foo.c # Source files.
foo.h
SConscript
/other # Other top-level directories with no source code.
/stuff # However, there are other assets I may want to build.
README # Other top-level files.
SConstruct
The problem is that when I run scons from the top-level directory, it calls gcc from that directory without cding into src, like this:
gcc -o src/foo.o src/foo.c
This is problematic for several reasons:
Within my program, I #include files giving the path relative to the src directory. For example, more.c could include foo.h with #include "foo.h". This fails because GCC is run from the parent directory. I don't want to change my includes to #include "src/foo.h".
I use the __FILE__ special macro for things like logging. When built from the top-level directory, GCC puts "src/" at the front of all filenames, since that was the path it was given to compile. This may seem picky, but I don't want that, because I think of my source tree as being relative to the src directory.
(Edit: I should add that obviously #1 can be fixed by adding -Isrc as a flag to GCC, but this seems like more hacks around the main issue.)
How can I make SCons cd into the src directory before calling gcc?
I don't want to get rid of the src directory and move everything up, because there are lots of other (non-code) files at the top level.
I don't want SCons to cd into every subdirectory. It should just cd into src and then build all files in the hierarchy from there.
I could solve this by moving SConscript inside the src directory and running it from there, perhaps using a Makefile at the top level. But this seems quite hacky, and I also do want to use SCons to build (non-code) assets in other directories than src.
I've read that you can make a custom Builder and make it change directories. However, I do not want to write a whole new Builder for C/C++. Is there a way to modify the behaviour of an existing builder without writing one from scratch? Also, on one forum, someone said that changing directories from within a Builder would break parallel builds since it would change the directory that other tasks are building from. Is this true?
This behavior is just how SCons works, and its not possible to avoid/change. I've been looking for some supporting documentation in its favor, and havent found any. Its just something Ive become used to.
As you mention, the include paths are simple to fix. The harder part is the __FILE__ macro. I hadnt ever noticed this until you mentioned it. Unfortunately, I think the only way around this is to strip the path in the logger, which is a rather ugly fix.
You can add src to your env['CPPPATH'] which will fix the include paths.
env.Append(CPPPATH=[Dir('src')])
However, this doesn't solve the problem with __FILE__.

CMake, build options

I can't seem to find much about this, so maybe it isn't possible... or I am searching with the wrong keywords.
Anyway, I have a directory of source. Let's say that there is a folder within Source called Tests and another called Products. I have the usual hierarchy of CMakeLists.txt files so that I can build all the source in each directory and subdirectory, etc... What I want to know is if it is possible to pass a command line argument with cmake so that it will only build the tests folder or the source folder.
e.g. something like cmake TEST ..
Thanks
Of course you can use flags.
if(TEST)
include needed folders
else()
do something else
endif()
And call cmake like this:
cmake -DTEST=1 ..
You can create them as different targets. CMake will configure all of them, but then you can run make test or make product. An example would be:
project(myProject)
add_subdirectory(tests)
add_subdirectory(products)
add_executable(test EXCLUDE_FROM_ALL ${TEST_SRC_FILES})
add_executable(product EXCLUDE_FROM_ALL ${PRODUCT_SRC_FILES})
In each subdirectory you would have a CMakeLists.txt that builds the source file variables. The EXCLUDE_FROM_ALL means that just typing make won't build either tests or products, but you can decide if you want that to happen or not.
To build, you can do make test or make product and it will build only that target (and any dependencies).

Resources