Organize multiple projects with cmake and QT - c++

cmake is even easier than would I could ever hope for. At the moment what I ask myself is, how can I create one (or multiple) CMakeLists.txt file(s) such that the following project structure works:
my workspace
src
project1
project2
build
project1
project2
More concretely, I have the following two constraints that should determine both my project structure and my CMakeLists.txt file:
1) I use git and would like to commit only CMakeLists.txt and my source files, build should only by generated for each particular user who would like to work on this project via an IDE of his desire
2) If someone clones my repository, he will be able to run cmake that builds the directories as described above (/my workspace/build/project1 and /my workspace/build/project2) for the IDE that he/she desires, such that he can work on this project
3) The src directories should be clean such that anyone who works on the project can do this with his/her desired IDE, change src files and maybe CMakeLists.txt and afterwards commits what he/she has done, so that everyone else can checkout again and work with it in the same way
Huge advantage for collaboration in that way! However, cmake seems to build everything just into the directory where cmake is called from.
Now, for the questions:
a) In order to create my desired directories with the corresponding builds, is there any other way than to call cmake from newly build /my workspace/build/project1 and /my workspace/build/project2 folders?
b) Do you prefer a different directory structure to collaborate?
c) If yes to b), where do you put your CMakeLists.txt file(s), from where do you call cmake from and what is the general process for building?
d) QT creates moc files which seems to work fine. Do you commit them in any way or are they just put into the build directories for everyone who checks out and you make sure that they can be used?

Build directories aren't your thing to decide. Other developers will choose where to put the build directories (I have an 'outside' setup with eclipse: https://stackoverflow.com/a/38140914/4742108). Build directories are not commited into the repository.
CMakeLists.txt is per-project. You have two projects, so they shouldn't be related in any way from the point of view of CMake. Also, you should decide whether it's necessary to commit them to the same repository.
The moc files are not commited anywhere. They are local for each build, just like *.o files or any intermediate stuff that compiler generates.

Related

CMake solution sub-directory

I have a big CMake solution which contain 5 projects. On this 1 project creates Main executable and rest of the 4(3 static + 1 dynamic) projects creates libraries which are linked to the main project.
MainSolution:
|-MainExecutablePrj
|-StaticLib_1Prj
|-StaticLib_2Prj
|-StaticLib_3Prj
|-DynamicLib_1Prj
The entire project is to be build for both windows and linux platforms. Now I need to create an Sub directory under MainSolution and create some testcase projects which uses the DynamicLib_1 (.lib/.so). So far what I have done is I will have different solution for each test cases and copy the required .h files and .lib(.so) files and build the test case solutions.
Its very hard for me to maintain the source code and whenever there is an change on the dynamic library I need to copy all the necessary files and rebuild the test cases again.
So I wanted to include the Test cases solutions inside my main project, so that whenever I change dynamic library project it builds the test case projects as well.
I very well know to add those test case solutions as projects under the MainSolution but I wanted to create sub-directory and put all the test case projects under that folder.
MainSolution:
|-TestCasesFolder
|-TestCase_1Prj
|-TestCase_2Prj
|-...
|-MainExecutablePrj
|-StaticLib_1Prj
|-StaticLib_2Prj
|-StaticLib_3Prj
|-DynamicLib_1Prj
Can someone help me on this
It should not be necessary to copy any files.
Let CMake find the built libraries with find_library and add a hint to the path of subdirectories build folder
Let CMake include the header files from your subproject with include_directories. Add a prefix to make it platform independent.
Regarding the tests:
All unit tests for a subproject should be places within the structure of this project and not in the root project. Place all integration tests in the root project or a separate test project as part of the root project.
Example Structure

How organize opensource C++ project with IDE to share it on github

I would like to know (according to Principle of Least Surprise) how to organize C++ project with tradeoffs, for example, so that it can be easily shared over git (e.g. on github), or make it easy for anybody who is interested to import the source files into his environment.
As an example I would refer to Code::Blocks since I currently starting to use it, but the question should be more general for any IDE.
How I currently do:
I have directory structure like this ( dictionaries starts with /, comment with // ):
/.git // git repo metadata
/common // source code shared between projects
/math
/physics
/GraphicsUtils
/common_data // shared data (resources)
/apps // executable projects ( use cases )
/SailWar // game about fighting sail boats
/AirCraftSimulator
/SpaceShipSimulator
/libs // dynamic library projects
/OrbitalMechanics
In each project folder for particular executable program I have this structure:
/SailWar
/bin // CodeBlocks binary output
/data // my datafiles (resources) required for program to run
/src // my source code
/obj // CodeBlocks compiled objects files
main.cpp
makefile
program.x // binary
SailWar.cbp // CodeBlocks project file
SailWar.depend // CodeBlocks .depend
SailWar.layout // CodeBlocks .layout
test // bash script to make clean, make and run the binary
In .git/info/exclude I have:
*~ *.pyc *.o *.a *.so *.x bin obj .depend .layout
to make sure that only source files ( not the output and temporary files ) are uploaded to github
What I'm not happy with / sure about:
Should I keep ( track ) .depend .layout in git ?
Is CodeBlocks project .cbp protable and genral enought or I have to still keep the makefile way of compilation. Best would be if CodeBlocks can use makefile instead of .cbp
when compiled binary is put to /bin it does not have correct path to /data
I'm not exactly sure how to best connect shared code /common and resources /common_data. Currently I put ../../common into compiler search paths ... but I'm not sure if it is the best way.
I would probably prefer to make a single project file for everything (all executables, all libraries in one). I think it would make it more clear for any potential user who download it from github. But that is probably not possible (?) (I was reading this question about that.)
I am currently undertaking a pretty big project with many moving parts, so I had to come up with a good way of organizing all my paths so that there was some kind of order to the madness.
Basically, I have a root directory where all my project subfolders reside, and then each project folder has an include folder, but all projects use the same output folder. I also use different .workspace files to organize the different projects into groups. This way I can keep a deterministic folder structure for all my project (all inside the same folder), but still keep them organized.
\root\develop\.workspace
\root\develop\[project]\.cbp
\root\develop\[project]\include
\root\develop\[project]\obj
\root\develop\bin
\root\develop\external\bin
\root\develop\external\include
If you want, you can take a look by checking out the source tree and going through the numerous projects and project options. THis directory structure supports multiple libraries, executables, and external dependencies. Its definitely worth a look.
https://github.com/zackeryfix/ngen/tree/master/develop/now
Making your project depend on IDE is bad idea. It is one of the reasons cmake was created. As such, I'd recommend you to use CMake as your build system and whatever IDE you like, that supports managing CMake projects.
My personal choice is KDevelop, for instance.

Using Cmake with Qt Creator

I would like to use Qt creator and Cmake together (please, don't ask me about my motivation, accept this as a given.)
I successfully set up Qt creator to use cmake "Cmake": see this, this and this documents regarding how I did that.
I successfully create hello world project, but I can't create files in project,
only add existing files to project tree and after that adding it to cmake list.
Standard operation of Qt creator "Add New..." doesn't work and I can't find why.
Is there anybody who uses Qt creator and "Cmake" together? Is the combination actually possible?
Note: I'm using Qt creator v2.4.1.
You can add files using glob expression in your CMakeLists.txt, like this:
file(GLOB SRC . *.cpp)
add_executable (your_exe_name ${SRC})
Cmake will pick your new cpp files next time you run it and QtCreator will show them in the project browser.
Update
This solution may be useful but as noted in comments - this is not a good practice. Every time somebody add new source file and commit changes, you need to rerun cmake to build all the sources. Usually I just touch one of the CMakeLists.txt files if my build is broken after I pool recent changes from repository. After that make will run cmake automatically and I didn't need to run it by hands. Despite of that I think that explicit source lists in CMakeLists.txt is a good thing, they called thing CMake Lists for a reason.
When you add new files in QtCreator using the "New File or Project..." dialog it only creates the files on disk, it doesn't automatically add the files to the CMakeLists.txt. You need to do this by hand by editing the CMakeLists.txt file.
The next time you build the project, CMake will be re-run, and QtCreator will pick up the new files and show them in the project browser.
I solve this problem that I added new files in standard way (CTRL+N), then added needed files in CMakeLists. After that, right click on project in project tree view and choose option Run CMake. After this, files showed in project list tree. Only build was not enough.
I tested here and happened the same behavior because those options you were asking were really disabled.
Use File -> "New File or Project..." or CTRL+N to add new files and after that add to CMakeLists.txt
I'm adding an updated answer for newer versions of QtCreator (4.x, I don't know precisely which release but at least from 4.7). In the Tools > Options... menu, choose the Build & Run section and then the CMake tab. You will see the Adding Files settings, and you can set it to Copy file paths :
This way, when you want to add a new file to your project, in the Project view, right click on the desired CMake Executable/Library's name and select Add New..., go through the Add dialog, and when you'll validate the dialog, QtCreator will open CMakeLists.txt in the Editor view. Finally, paste the content of the clipboard at the end of the corresponding source file list and save CMakeLists.txt. The CMake project will be parsed, and your new file will show up in the Project view.

What is the best dir structure for building obj and exe files?

I have been crafting a makefile for a while now. It supports easy creation of exe, lib and dll type projects, through the use of includes.
Now that I have started using mercurial again, I notice that everything is nice and clean until I do a build. You see I have my object files going into sub directories below the source directory for each sub-project. And I have my lib, exe, and dll files being built to directories which are below the main working directory. This means whenever I do hg status, it will list these temporary binary files with '?', which is visual clutter I don't want. (It's not mercurial's fault and of course I wouldn't be so naive to check them in to the repo or anything like that.) I only want hg status to uncover files that I may have forgot to add properly, not these temporary built ones.
The current dir structure is like this:
projroot
-- subproj1 (for source files)
-- subproj1/intr (for object files, release build)
-- subproj2 (for source files)
-- subproj2/intr (for object files, release build)
-- bin (for exes and dlls)
-- lib (for libraries that I build)
So I'm thinking of restructuring the makefile to keep the files that are built (objs libs dlls and exes) outside the working directory. Do most people keep all the binaries in a directory one level above projroot to avoid SCM seeing them? There must be some best practice. What I was using seemed good but it's a bit dated I think, certainly since I have seen ant's way of having a completely seperate tree for Java src and classes.
What about this structure?
projroot (contains common makefile includes and repo in here)
-- subproj1 (for source files)
-- subproj2 (for source files)
build
-- subproj1/intr (.o / .obj files in release build)
-- subproj1/intd
-- subproj2/intr
-- subproj2/intd
-- lib (all built libs)
-- bin (all built exes and DLLs)
The build directory is outside of the working directory and so is ignored by whatever SCM we would use.
Your answer has to take into account the common makefile source code in projroot and the fact that there are multiple projects, each with their own collection of built binaries which you may possibly want to distribute seperately.
Personally I prefer such a directory structure as I don't like any of the source subfolders to be polluted with compiled intermediate files. Doing a clean is just a matter of deleting the output folder
projroot
-- subproj1 (for source files)
-- subproj2 (for source files)
-- output/bin (for exes and dlls)
-- output/lib (for libraries that I build)
-- output/subproj1/ ( for *.o files )
-- output/subproj2/ ( for *.o files )
This has the added benefit that I can set the whole of output folder to be ignored by the source control management and I don't have to to check the SCM software to see what files are generated and what are revision controlled.
Since you already have the Makefile overhaul answer, I'll submit a mercurial answer.
You can simply teach Mercurial to ignore some files, and you can easily do so by pattern:
// .hgignore file
syntax: glob
# Object Files
**/intr/
# Libraries
lib/
# Binaries
bin/
Quick and dirty, as we like.
On the other hand, I find rearranging the Makefile to have a single polluted dir better than keeping all the generated files scattered to the wind.
Couldn't you just set up your .hgignore file to hide the binaries from hg status? That seems far simpler than rearranging your entire project tree.
Mercurial will look for a file named .hgignore in the root of your
repository which contains a set of glob patterns and regular
expressions to ignore in file paths.

Set Build output directory in Eclipse - c++

I have a program which consists of multiple projects in eclipse (working under ubuntu and the projects being in c++), these projects consist of a main executable file, and other shared objects files and static libs.
I want all these projects when built to output their files to one common binary folder, instead of their respective debug folders. This is to make linking easier with the main executable. If there are better solutions please also feel free to share.
Unfortunately, I have found that the C/C++ Build tab does not allow you to set the build location unless you are creating your own makefile.
You've likely found that the Builder Settings tab under Project Properties>C/C++ Build is all grayed out in a default C/C++ project. This is because CDT nominates the internal builder by default for new projects. To change this, you can go to Project Properties>C/C++ Build>Tool Chain Editor and change the Current Builder to Gnu Make Builder. Next, go to Project Properties>C/C++ Build and change the Builder Type to External Builder. You can now opt to create your own makefile for the project, if you like; though I'd recommend leaving CDT to build the makefile automatically for now.
I have the same project requirements of outputting to a /project_path/bin (though I still maintain separation between Debug and Release builds). To do this, I perform a copy operation on the output as a post-build step.
To do this, go to Project Properties>C/C++ Build>Settings and select the Build Steps tab. In the Post-build steps under Command:, enter:
cp ${BuildArtifactFilePrefix}${BuildArtifactFileName} "/path/to/bin/directory/";
Obviously replacing the "/path/to/bin/directory/" as required.
I personally prefer to maintain my project files in a workspace/build directory; copying binaries to a workspace/bin directory and libraries to a workspace/lib directory. At first I found this copy workaround to be an inconvenience, but have come to appreciate it because it isolates the interstitial build files from the final binary/library.
For binaries, I would use:
cp ${BuildArtifactFilePrefix}${BuildArtifactFileName} "${WorkspaceDirPath}/bin/";
For libraries, I would use:
cp ${BuildArtifactFilePrefix}${BuildArtifactFileName} "${WorkspaceDirPath}/lib/";
I include the variable "${BuildArtifactFilePrefix}" because CDT includes "lib" as a default prefix for static libraries, which I actually prefer.
You just need to ensure that the target directory exists before building; Eclipse/CDT will not create the directory for you.
Also, just remember that these copies will be left behind in the /bin or /lib directory on clean, but overwritten on any subsequent rebuild.
Try Project->Properties
Under C/C++ Build->Settings you have a tab called Build Artifact.
Under there you have Artifact name. This defaults as ${ProjName}.
Modify this to specify a relative directory path to where you actually want the final file to end up. So could be ../../lib/${ProjName}
The intermediate files (.o and .d) will still build to the sub-directory (Debug or Release) but I guess it's better off if they are there anyway and it is only the finally built library for which you want to change the build path.
If you find it inconvenient typing the relative path like this, I use Environment to create environment variables with relative paths taking me back to a "root". One of this I have is ${LIBDIR} and this is a relative path from where the project gets built. It is usually used for linking in other libraries, but can also be used as a target. Then you would set Artifact Name to ${LIBDIR}/${ProjName} which works well if you use different directories for debug and release builds.
Go to
Project Properties -> C/C++ Build -> Settings -> (tab) GCC C++ Linker
The command line pattern is shown on the right side
${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX} ${OUTPUT} ${INPUTS}
Put in front of ${OUTPUT}
${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX} ${ProjDirPath}/bin/${OUTPUT} ${INPUTS}
or
${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX} MyMainProject/path/bin/ ${INPUTS}
From https://www.eclipse.org/forums/index.php?t=msg&th=207500&goto=665566&#msg_665566
In my project the build path defaults to the Build Configuration name, so I could use a ${ConfigName} macro to retrieve the build path in a post-build step:
${workspace_loc:/${ProjName}}/${ConfigName}/${BuildArtifactFileName}
Then you can copy target binaries to your common binary folder, or do something other in the build folder of that particular configuration.
If you open up the project's properties, there is a tab C/C++ Build. This has an option for build location, where you can specify the build directory. It seems you could change this for your multiple projects so that they share the same build directory.
Just happened to be working on something that led me down a similar path - so I'll offer it up as an alternate solution/reminder to myself:
In Eclipse (at least in Luna) the generated makefiles are actually rather decent and convenient. I personally like to create several build configurations (Release and Debug variants with 32 and 64 bit architectures), and supplement them with debug and run (F5 and Execute, respectively) configurations.
To continue: I have been toying with packaging on Debian and found - during the act of said toying - that I needed to create and test an install target. Eclipse neither generates for you, nor provides an interface to - a configuration - for customizing or adding an install target; Other than a place where you can specify that another target exists.
So technically Eclipse does provide an interface; kinda. Hence, I stumbled across the makefile.init, makefile.defs, and makefile.targets files.
Process/Workflow:
Create a file makefile.targets in the root directory of your eclipse project; In said file define an install target manually. This - of course - allows you to specify every little detail as you'd like, but with the added benefit of all of the configuration provided by Eclipse already complete and available to you for use with defining the rules for the specified target.
After defining the new target in the makefile.targets file, right click on your project's name or main cpp file in Eclipse's project explorer, and then select Make Targets->Build..., and finally Add to instantiate a pop-up. Alternatively, you could select 'create' in the last step instead of 'build' and it would provide the same pop-up required for the next part. Add the name of your new target and - leaving everything else at their default values - click ok
If you chose to add the new make target by right-clicking in Project Explorer and selecting Make Target->Build..., after adding the new make target you will be brought back to the first pop-up which resulted from selecting Build.... Otherwise, find your way to the Make Targets->Build.. pop-up now. Select the desired target and then click on Build.
Looking through Eclipse's auto-generated makefiles was an excellent way to learn the makefile syntax and overall structure, and get into some advanced usage of includes and conditionals.
Here are some portions of an example makefile, which - at least I hope - will demonstrate manually setting the output directory of a build:
prefix = /usr/local
bindir = $(prefix)/bin
sharedir = $(prefix)/share
mandir = $(sharedir)/man
man1dir = $(mandir)/man1
...
# Typical all target
all: <binaryname>
#Typical clean target
clean:
rm -f <binaryname> <objectname>.o
# Target invokes all, then installs to specified locations
install: all
install <binaryname> $(DESTDIR)$(bindir)
install -m 0644 <objectname>.1 $(DESTDIR)$(man1dir)