Add files with target using CMake - c

I am working using CMake on a little C project using OpenGL. To be able to run, my executable needs to access some resources files such as 3D meshes, textures or shader program sources.
When I run the generated executable, the current folder is the directory where it is created. This directory may differ depending on the binary tree location (out of source ? insource ? anywhere in the coputer). But my resources are located near my source tree.
I would like my CMakeLists.txt to copy the resource folder in my executable output directory but I have not a good idea of the way to do that. Besides, I am not sure this is a "best practice" of CMake.
Thank you for reading :)

You have 2 useful variable to do so: CMAKE_CURRENT_BINARY_DIR and CMAKE_BINARY_DIR, the former refers to the current CMakeLists.txt output directory, the latter refers to the top level project output directory.
Most of the time, you handle resources near the executable depending on it, then you'll certainly want to refer to CMAKE_CURRENT_BINARY_DIR.
configure_file(
"MyResourceDir/myresource"
"${CMAKE_CURRENT_BINARY_DIR}/" COPYONLY
)
This command will copy resource of the CURRENT_CMAKE_SOURCE_DIR/MyResourceDir named myresource in the directory matching the current CMakeLists.txt.
You can glob files of your MyResourceDir and loop on it (maybe there is also some function to copy directory instead of list of files).

Related

How to add subdir sources in target? [duplicate]

I have project which has not been divided into libraries, but the source is organized in a directory tree. I do not know how to tell cmake to go down a directory, then add the source in that directory to project defined in the parent directory. I have attempted the following:
in project/source/CMakelists.txt:
set(SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/unitTest/main.cpp
)
add_subdirectory("${PROJECT_SOURCE_DIR}/folder1")
add_executable(UnitTestRNG ${SOURCE} ${HEADERS})
then in project/source/folder1/CMakeLists.txt:
set(SOURCE
${SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/file1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/file2.cpp
)
set(HEADERS
${HEADERS}
${CMAKE_CURRENT_SOURCE_DIR}/file1.hpp
${CMAKE_CURRENT_SOURCE_DIR}/file2.hpp
)
using some message() statements, I have found that the the child folder will get the contents of the SOURCE variable, but it's new assignment to that variable will not persist on returning to the parent CMakeLists.txt
Looking for examples and at the cmake tutorial has led me to the conclusion that:
- Source file structures are usually flat within a project
- If code is divided into folders, it is usually is divided into corresponding libraries.
I wonder if there is some "best practice" from which I am deviating by attempting this structure.
Since CMake 3.1 there is a new way to add source from subdirectories: target_sources
Say you have root_dir and root_dir/sub_dir and source files in both. With target_sources you can do this:
In root_dir/CMakeLists.txt define the target
add_library(some_target main.cpp)
add_subdirectory(sub_dir)
In root_dir/sub_dir/CMakeLists.txt add sources:
target_sources(some_target PRIVATE more_cool_stuff.cpp)
some_target will now contain both source files.
It is also possible to use other commands in root_dir/sub_dir/CMakeLists.txt using some_target, for example target_compile_definitions which is quite convenient to add compilation definitions.
I learned about target_sources here, check it out if you want more explanation and examples
Like the second part of arrowdodger's answer says:
in project/source/folder1/CMakeLists.txt:
set(SOURCE
${SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/file1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/file2.cpp
PARENT_SCOPE
)
set(HEADERS
${HEADERS}
${CMAKE_CURRENT_SOURCE_DIR}/file1.hpp
${CMAKE_CURRENT_SOURCE_DIR}/file2.hpp
PARENT_SCOPE
)
Can't you just set all your sources in project/source/CMakelists.txt then?
Anyway, what you need is PARENT_SCOPE or CACHE option on set command.

(CLion/CMake) Why does my c file not belong to any target project when it is saved within the project directory?

Preface: I am very new to c and CLion, so apologies in advance if my phrasing is very wrong.
Essentially, I have an assignment that involves two c files (a "main", and one performing a conversion between imperial and metric units). The main c file simply #include-s the conversion file, performs a function within the conversion file, and prints the resulting value to the user. Simple enough, but I keep getting a message every time I try to run it:
"undefined reference to 'conversion'"
I have tried to suss out the problem, and my only idea relates to the banner at the top of conversion.c which says "This file does not belong to any project target, code insight features may not work properly.". I do not understand why I receive this message, because conversion.c and main.c are both within the main project directory, and this setup worked perfectly fine in my previous assignment.
I have searched for solutions online, and the only one that seemed to make sense was to update my CMakeLists.txt file to include add_executable(project conversion.c). This is what my CMakeLists.txt file looks like before I add this line:
cmake_minimum_required(VERSION 3.12)
project(project C)
set(CMAKE_C_STANDARD 11)
add_executable(project main.c)
However, when I add it, I get the error:
CMake Error at CMakeLists.txt:7 (add_executable):
add_executable cannot create target "directory" because another
target with the same name already exists. The existing target is an
executable created in source directory
"/home/john_s/CLionProjects/project". See documentation for
policy CMP0002 for more details.
Presumably this is because the previous line I have (add_executable(project main.c)) is linking to the same directory, but I have no idea how to resolve this. Any suggestions?
From cmake manual:
add_executable(< name> [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL]
[source1] [source2 ...])
Adds an executable target called to be built from the source files listed in the command invocation. (The source files can be omitted here if they are added later using target_sources().)
So to combile a single executable using two source files, you just use:
add_executable(target_name source1.c source2.c)

How to specify a directory for scons to store all the .o(intermediate) files?

How to specify a directory for scons to store all the .o(intermediate) files?
My question is: what's the way to set something like a global flag, so that each 'Object' command will generate .o files in a solid directory, and 'Program' command will generate in some other directory? I don't wish to have some variables so that each 'Object' and 'Program' command will explicitly use this variable: it's ugly and coupled. I just wish to have something like a compile hook.
For example, I've got a testSystem.cpp, and in SConstruct I have:
Program('testSystem.cpp')
Then scons will first compile a testSystem.o file, and link to a testSystem executible.
I know I can explicitly specify where where the binary file is stored:
Program('bin/testSystem','testSystem.cpp')
Well, the object file is still under current directory. I can do this:
testSystem_obj=Object('obj/testSystem.o','testSystem.cpp')
Program('bin/testSystem',testSystem_obj)
Now I have .o under ./obj and executible under ./bin. No problem.
But, this means for each file, I've to manually write 2 lines, 1 line to tell scons to generate the object file under ./obj, another line to generate the file under ./bin. If I wish to reorganize my whole project, I've to modify all my SConstruct/SConscript files. I've got a big project and don't want to do this.
Any hints? How to do this with scons?
Sort of.
SCons supports VariantDir's which allow separating the source from the build product.
Take a look at:
http://scons.org/doc/production/HTML/scons-user/ch15.html

How does MAKE remember the file timestamps

I've found this question which is basically asking the same, but got no real answer.
Where is the make's config file / database file where it remembers the file timestamps, so it can tell what changed? I checked and there's no .make or similar in my project, nor in the home directory.
Or does it somehow store the information inside the files themselves, perhaps by modifying the timestamps? (That sounds fishy though)
There is no such "database". The program simply compare the filesystems modification and creation timestamps of source and target files.
Lets say you have the following rule:
some_target: some_source_1 some_source_2
Then if the modified timestamp of either some_source_1 or some_source_2 is later than the modification/creation time of some_target then the rule will activate and the target will be rebuilt.
Makefiles describe targets and dependencies. Make executes commands to create/recreate the target(s) if necessary.
If the target doesn't exist, then make will try to create it.
If the target does exist, make compares the modification times of the target and its dependencies. If any of the dependencies was modified after the target was modified, then make will execute the command(s) to regenerate the target.
For example, for C files the target is the corresponding .o file and the dependency is on the file containing the C source code (and possibly some include files). If the .c file is newer than the .o file, then make runs the C compiler. This will generate a .o file with a newer modification time than the .c file.

Crossprofiling with gcov, but GCOV_PREFIX and GCOV_PREFIX_STRIP is ignored

I want to use GCOV to make code coverage but the tests will run on another machine. So the hard wired path to .gcda files in the executable won't work.
In order to change this default directory I can use the GCOV_PREFIX and GCOV_PREFIX_STRIP env vars, as it's said here.
Here my commands I used:
$ export GCOV_PREFIX="/foo/bar"
$ export GCOV_PREFIX_STRIP="3"
$ gcc main.c -fprofile-arcs -ftest-coverage
$ strings a.out | grep gcda
/home/calmarius/blahblah/main.c.gcda
The path remains the same.
Anyone have experience with this?
The environment variables are taken into account when you run the code.
Set them to the appropriate values on the target machine before you run your tests, and the .gcda files will be generated where you want them.
************ ARRRRGGGGGHHHHH ************
Please, please vote for Mat's answer.
The environment variables are taken into account when you run the
code.
This one sentence is apparently missing from EVERY document I have read regarding how to relocate the output !
In fact , allow me to expand that answer just a bit.
GCOV_PREFIX is a runtime - as apposed to build time - environment variable and determines the root directory where the gcov output files (*.gcda) are written.
GCOV_PREFIX_STRIP=X is also a runtime variable, and has the effect of stripping X elements from the path found in the object files (strings XXXX.o)
What this means is:
When you build your project, the object files are written with the full path to the location of each source file responsible for each object file embedded within them.
So, imagine you are writing an executable MyApp and a library MyLib in a directory stricture like this:
/MyProject
|-MyApp
|--MyLib
Notice MyLib is a subdirectory of MyApp
Let's say MyApp has 2 source files, and MyLib has 3
After building with the "-coverage" flag, you will have generated
5 .gcno files, 1 for each object file.
Embedded in the .o files for MyApp will be the absolute path **/MyProject/MyApp/**a_source_file.cpp Similarly, embedded in the .o files for MyLib will be the path **/MyProject/MyApp/MyLib/**another_source_file.cpp
Now, let's say you're like me, and move those files onto a completely different machine with a different directory structure from where they got built. In my case the target machine is actually a totally different architecture. I deploy to /some/deploy/path not /MyProject on that machine.
If you simply run the app, gcov data will try to write corresponding .gcda files to /MyProject/MyApp and /MyProject/MyApp/MyLib for each object file in your project, because that's the path indicated by the .o files, and after all, MyApp, and MyLib are simply collections of .o files archived together, with some other magic to fix up funcitons pointers and stuff.
Chances are, those directories don't exist, and you probably aren't running as root (are you?), so those directories won't be created either. Soooo.. you won't see any gcda files within the deploy location /my/deploy/path.
That's totally confusing, right !?!??!?!?!?
Here's where GCOV_PREFIX and GCOV_PREFIX_STRIP come in.
(BAM ! fist hits forehead)
You need to instruct the ****runtime**** that the embedded path in the .o files isn't really what you want. You want to "strip" some of the path off, and replace it with the deploy directory.
So, you set the deploy directory via GCOV_PREFIX=/some/deploy/path and you want to strip the /MyProject from the generated .gcda paths so you set GCOV_PREFIX_STRIP=1
With these two environment variables set, you run your app and then look in
/some/deploy/path/MyApp and /some/deploy/path/MyApp/MyLib and lo and behold, the 5 gcda files miraculously appear, one for each object file.
Note: the problem is compounded if you do out of source builds. The .o points to the source, but the gcda will be written relative to the build directory.

Resources