What I am asking might sound illogical but it is very important for me.
Lets assume we have such file and folders
project_rat/
project_cat/
project_rabbit/
Makefile
The user might add any project folder here. The Makefile has the following config variable:
model_name:= project_rat
The user might change this model_namevariable to any of the folders.
and the makefile compiles the appropriate project folder.
g++ -std=c++11 $(model_name)/main.cpp
Now my problem is that I want to add a debug/release variable into the Makefile and based on that I turn on the appropriate optimizer. I want this variable be determined from my project. It must depend on each individual project. One project might need -O2 and the other -O3.
Can I influence Makefile from any C++ code?
Assuming that you're using GNU make (a safe bet, given your usage of gcc), add this to your Makefile:
include $(model_name)/Makefile.opts
Now, create a file Makefile.opts in each project directory, that sets the Makefile options for that project.
This works just like the C/C++ #include preprocessor directive.
If you do not want to require a Makefile.opts in each project directory, use sinclude instead of include.
Related
I have a Qt project which requires a library (gphoto2) to enable some features that are not essential. I'd like to add some sort of configuration option to my qmake or make call to enable features using this library, so I can compile without it being installed.
What is the best way to configure something like this?
I guess I need some way to add a define based on a compiler parameter, which I can query in my code using #ifdef ...
I assume you use make (without qmake). It is reasonable and quite easy to use GNU make (alone) on Qt projects. You could use some other build automation tool like ninja.
Then you could decide to enable that Gphoto feature by compiling your code with -DWITH_GPHOTO and using #if WITH_GPHOTO in your C++ code.
You would compile by adding
CXXFLAGS+= -DWITH_GPHOTO
in your Makefile
I won't call that a "custom compiler flag" (e.g. like GCC plugins can provide) but a preprocessor flag. It is pretty standard practice.
Maybe you also want to pass such flags to moc. Then your Makefile is running moc thru some rule and command, which you could tailor too.
BTW, you might consider GNU autoconf or some other Makefile generator like cmake. I don't think you should spend too much time on these...
PS. I don't know how that idea translates into qmake and leave you to find out.
Assuming, you are using qmake, you can add a preprocessor definition depending on the existence of a file or an environment variable.
You could add a qmake project for compiling your external library and place it relative to your own project by default.
LIBGPHOTO2_PATH = $$getenv(LIBGPHOTO2PATH)
isEmpty(LIBGPHOTO2_PATH): LIBGPHOTO2_PATH = ../../libgphoto2
exists($$LIBGPHOTO2_PATH/libgphoto2.pri): include($$LIBGPHOTO2_PATH/libgphoto2.pri)
In libgphoto2.pri you add a preprocessor definition to indicate the presence of libgphoto2, add include and linker paths etc.:
DEFINES += WITH_LIBGPHOTO2
In the code of your dependent project, you check for the presence using #ifdef.
Instead of creating a qmake-project to compile, you could also check for the presence of the compiled library at a given path and set values directly (I don't know how libgphoto compiles, so I assume a default directory structure with include/, lib/ etc):
LIBGPHOTO2_PATH=$$getenv(LIBGPHOTO2PATH)
isEmpty(LIBGPHOTO2_PATH): LIBGPHOTO2_PATH = ../../libgphoto2
exists($$LIBGPHOTO2_PATH/include) {
DEFINES += WITH_LIBGPHOTO2
INCLUDEPATH += $$LIBGPHOTO2_PATH/include
LIBS += -L$$LIBGPHOTO2_PATH/lib -lgphoto2
}
You should however consider to move to something more modern like qbs, which is a lot faster, more flexible and easier to read.
My project is quite simple but I like to keep files in different folders for clarity. For instance I have three folders.
An Output folder that contains all the classes used for the output. (for now only Output.cc and Output.h).
A Math folder, containing all of the classes related to math. (vector.cc, vector.h, randomgen.h, randomgen.cc, etc)
A Tests folder where there are different cpp files each containing a main function. (Output_test.cc, vector_test.cc, etc)
How can I create a CMake script that complies all of the different main function of the different test programs using the classes that are in different folders?
In addition, I didn't see where the compiler, and its options, are specified in a CMake file.
How to specify the compiler?
There are a few ways to specify the compiler you want to use. Settings environment variables, defining compiler variables, or designating a generator.
Settings Environment Variables
There are two ways to use environment variables to help CMake determine which compiler to use during a CMake configuration. Using the PATH variable or the CC and CXX variables.
PATH
Make sure the path to your desired compiler is first in the list. If you don't want to modify your path, then use the 2nd option.
CC & CXX
CMake reads the variables CC and CXX to determine the path for the C compiler and C++ compiler respectively. Note that the first time CMake is configured for a project it will cache these paths, and look to the cache first for all future configurations. So if you wish to change the compiler path, be sure to delete the cache file CMakeCache.txt. As HughB pointed out, there is a good example of this given by Guillaume
Defining Compiler Variables
Similar to using CC and CXX, there are CMake variables that can be defined at the commandline to choose the desired compiler. They are CMAKE_C_COMPILER and CMAKE_CXX_COMPILER. You can set them using the -D option and they use the same values as CC and CXX. Note, just like CC and CXX these are cached after the first CMake configuration.
Example
cmake -DCMAKE_CXX_COMPILER=/usr/bin/g++4.6/g++ -DCMAKE_C_COMPILER=/usr/bin/gcc4.6/gcc <path to src>
Designating a Generator
The last way to choose the compiler is by using the -G option to select a generator. There are numerous generators to choose and I recently answered a question about them. I'm not going to go into too much detail about them in this answer, but you can read my other answer for more details.
Example
cmake -G "Unix Makefile" <path to src>
Don't Hardcode the Compiler
I recommend resisting the urge to "hardcode" the compiler in the CMakeLists.txt files. CMake is meant to be compiler independent and you should be setting the compiler information external of the CMake files. Use one of the methods mentioned above to keep your CMake files portable and to avoid confusion if yourself or someone else wants to build the project with a different compiler.
Related references. (Disclaimer: Written by me)
What is a CMake generator
Understanding the Purpose Behind CMake
How to Compile Multiple Executables?
As HughB mentioned use add_executables. You could also create separate libraries for each folder group, there are many ways to organize your project. I'm going to keep it simple and give an example that builds two executables in the same project.
For this example I created 5 files:
include/Helloworld.h
#include <stdio.h>
src/HelloWorld.cpp
#include "HelloWorld.h"
int main()
{
printf("Hello World!\n");
return 0;
}
include/HelloWorld2.h
#include <stdio.h>
src/HelloWorld2.cpp
#include "HelloWorld2.h"
int main()
{
printf("Hello World2!\n");
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
# This is required to compile and must contain the paths to
# all of the header files
include_directories(include)
# These are optional, but are added to be passed to the
# add_executable command so that the headers are accessible
# from within the project
set(HW_INCLUDES include/HelloWorld.h)
set(HW_INCLUDES2 include/HelloWorld2.h)
project(HelloWorlds)
# Required sources
set(HW_SOURCES src/HelloWorld.cpp)
set(HW_SOURCES2 src/HelloWorld2.cpp)
add_executable(HelloWorld ${HW_SOURCES} ${HW_INCLUDES})
add_executable(HelloWorld2 ${HW_SOURCES2} ${HW_INCLUDES2})
When this project is built there will be two executables: HelloWorld.exe and HelloWorld2.exe.
Consider putting the code that will be used in different program mains in a library. Use the add_library command to do make a library. You could have a directory hierarchy like this:
TopDir
CMakeLists.txt
MyLib
CMakeLists.txt
vector.cc
vector.h
....
MyExe1
CMakeLists.txt
main1.cc
MyExe2
CMakeLists.txt
main2.cc
Use add_subdirectory in your top level cmakelists.txt to traverse the directories. In the dirs that build executables, use add_executable and target_link_libraries. If you named the library MyLib then your target_link_libraries command would look like
target_link_libraries( exe1 MyLib )
In regard to overriding the compiler, see how to specify new gcc path for cmake
Let us assume that in first.h we have #include "aaa/second.h" and in the aaa/second.h we have #include "bbb/third.h". I think that in the "default settings" the compiler will complain if "third.h" is not located in "aaa/bbb".
Is it possible to change this behavior in such a way that the directory, in which the first.cpp is located is used to construct the full names in all includes?
For example, if "first.h" is located in '/home/bucky/' then #include "bbb/third.h" (from "aaa/second.h") should be interpreted as /home/bucky/bbb/third.h and not as /home/bucky/aaa/bbb/third.h.
EDITS
I cannot change the whole source code. In the code quotation marks are used instead of angle brackets.
I compile using g++ -std=c++0x name.cpp -o name in the command line. I do it in two different terminals. It looks like in the first terminal the working directory is used to construct the full names and in the second terminal it is not the case. I am almost sure that it happens because of the environment variables but I do not know which ones. So, my question is, to larger extent, what environment variables can force the compiler to construct full names using the working directory.
EDIT 2
In my test.cpp file I include "first.h". This inclusion does not cause any problem (complier sees "first.h"). The "first.h" file includes "ppp/second.h". It also causes no problems. But "ppp/second.h" includes "ppp/third.h" and this is the place where the problem appears. I think that the reason of the problem is that "second.h" tries to find "third.h" in the "ppp" subdirectory of the directory where second.h is located. In other words, second.h tries to find the third.h in the "ppp/ppp" subdirectory (because second.h is located in the ppp subdirectory).
In another terminal, the same compilation command, in the same directory does not cause any problem. The reason, is obviously in the values of the environment varibales.
Yes. The exact mechanics depend on the compiler but the short and the long of it is that you need to configure your compiler to include the project path in the search path. For GCC and clang that’s done via the -I command line flag (-I path/of/first.cpp). This configuration would usually be done in the project settings (if you’re working with an IDE), a Makefile or similar.
Since you’re talking about environment variables: the flags that are passed to the g++ and c++ compiler are controlled by the CXXFLAGS and CFLAGS variables.
You should set up include paths for your project globally. In your example, you would pass some option like -I /home/bucky to your compiler (if it is GCC or Clang). MSVC has analogous options.
(All #includes are searched relative to the include paths. The difference between <...> and "..." is that the latter also searches the current directory.)
Say I'm working on a library, foo. Within my libraries source files, I'd like to include headers the same way a user of my library would:
#include <foo/bar.hpp>
// code defining bar methods here
In boost for example, includes of other headers within boost are done that way, e.g. <boost/shared_ptr.hpp>, rather than the relative quoted "../shared_ptr.hpp" style. I looked at how some other libraries accomplish this and it appears they add a redundant directory to their file layout in order to do it, e.g. the boost code lives in "boost_1_4_1/boost" rather than just "boost_1_4_1/".
Switching to that scheme is annoying if you already have source control using an existing layout. What's the best way with GNU make to layer it on? My only thought is to add a target that all build targets depend on that makes a hidden folder with a symlink inside to my source tree, and add that hidden folder to the include path. Perhaps there's a less obfuscated way?
Couldn't you use -I gcc key of INC option for your Makefile?
gcc:
gcc -c -I/home/joseph/dev/foo/headers
Makefile:
INC=-I/home/joseph/dev/foo/headers
In this case you would have only one place to make this change, Makefile.
I have access to a large C++ project, full of files and with a very complicated makefile courtesy of automake & friends
Here is an idea of the directory structure.
otherproject/
folder1/
some_headers.h
some_files.cpp
...
folderN/
more_headers.h
more_files.cpp
build/
lots_of things here
objs/
lots_of_stuff.o
an_executable_I_dont_need.exe
my_stuff/
my_program.cpp
I want to use a class from the big project, declared in say, "some_header.h"
/* my_program.cpp */
#include "some_header.h"
int main()
{
ThatClass x;
x.frobnicate();
}
I managed to compile my file by painstakingly passing lots of "-I" options to gcc so that it could find all the header files
g++ my_program.cpp -c -o myprog.o -I../other/folder1 ... -I../other/folderN
When it comes to compiling I have to manually include all his ".o"s, which is probably overkill
g++ -o my_executable myprog.o ../other/build/objs/*.o
However, not only do I have to do things like manually removing his "main.o" from the list, but this isn't even enough since I forgot to also link against all the libraries that he happened to use.
otherproject/build/objs/StreamBuffer.h:50: undefined reference to `gzread'
At this point I am starting to feel I am probably doing something very wrong. How should I proceed? What is the usual and what is the best approach this kind of issue?
I need this to work on Linux in case something platform-specific needs to be done.
Generally the project's .o files should come grouped together into a library (on Linux, .a file if it's a static library, or .so if it's a dynamic library), and you link to the library using the -L option to specify the location and the -l option to specify the library name.
For example, if the library file is at /path/to/big_project/libbig_project.a, you would add the options -L /path/to/big_project -l big_project to your gcc command line.
If the project doesn't have a library file that you can link to (e.g. it's not a library but an executable program and you just want some of the code used by the executable program), you might want to try asking the project's author to create such a library file (if he/she is familiar with "automake and friends" it shouldn't be too much trouble for him), or try doing so yourself.
EDIT Another suggestion: you said the project comes with a makefile. Try makeing it with the makefile, and see what its compiler command line looks like. Does it have many includes and individual object files as well?
Treating an application which was not developed as a library as if it was a library isn't likely to work. As an offhand example, omitting the main might wind up cutting out initialization code that the class you want depends upon.
The responsible thing to do here is to read the code, understand it, and turn the functionality you want into a proper library. Build the "exe you don't need" with debug symbols and set breakpoints in the constructors and methods of the class. Step into them so you get a grasp on the functionality and what parts of the program are relevant and irrelevant to your needs.
Hopefully the code is under some kind of version control system that supports branching (such as Git). If not, make your own repository that does. Edit the files until you've organized them into a library and code that uses the library. Make sure it works properly within the context of the original program. Then turn around and use this library in your own program.
If you've done a good job, you might be able to convince the original authors to accept the separation back into their original codebase. If not, at least version control has your back so you can manage integration of future changes.