I have project that I am able to build a static library for using CMake but I am running into issue when trying to install my headers in the way I want.
Here is a very stripped down example of the file structure of my project:
.
├── modules
| ├── util1.cpp
| ├── util2.cpp
│ ├── module_a
| | |── file1.cpp
| | └── file2.cpp
│ └── module_b
| |── file3.cpp
| └── file4.cpp
└── include
├── util1.hpp
├── util2.hpp
├── module_a
| |── file1.hpp
| └── file2.hpp
└── module_b
|── file3.hpp
└── file4.hpp
The meat of my project is enclosed in a module directory with sub-modules within while the includes follow an identical format. Miscellaneous utility related headers are left floating in the includes dir.
Currently I am installing each header file individually as such:
set(PROJECT_INCLUDES
${PROJECT_SOURCE_DIR}/include/util1.hpp
${PROJECT_SOURCE_DIR}/include/util2.hpp
${PROJECT_SOURCE_DIR}/include/module_a/file1.hpp
${PROJECT_SOURCE_DIR}/include/module_a/file2.hpp
${PROJECT_SOURCE_DIR}/include/module_b/file3.hpp
${PROJECT_SOURCE_DIR}/include/module_b/file4.hpp
)
After installing my library to the necessary paths I am able to include as so:
#include <myproj/util1.hpp>
#include <myproj/file1.hpp>
#include <myproj/file3.hpp>
But wish to have a scheme more like so :
#include <myproj/util1.hpp>
#include <myproj/module_a/file1.hpp>
#include <myproj/module_b/file3.hpp>
What is the proper way to accomplish a process like this?
Since you want to install all files in a directory, use install(DIRECTORY):
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ # note: tailing slash is important here
DESTINATION include/myproj # installs files to e.g. <install root>/include/myproj/module_a/file1.hpp
)
There's also the possibility to include or exclude certain files using the FILES_MATCHING option, if you only want to copy some of the files. (This doesn't work well for including some files with a given extension while excluding others with the same extension though.)
Btw: I strongly recommend moving your headers to make the #include paths you want to use for users of the installed lib for build tree too. This way there's the option of using add_subdirectory instead of accessing an installed version for a project consuming the lib. Also it makes the project a bit easier to maintain, since you don't have to think about whether you need to use the include path for internal or external use...
The way I usually deal with modules Is to make subdirectories with proper src and include folders with their own CMakeLists.txt file and add them into the parent folders with add_subdirectories direttive.
I think that your header files, even though in different folders, are being included to the CMake project at the same level.
The add_subdirectories would make sense if your directory tree would look a bit different. But because you have seperated the header files from the implementation files - it would only lead to bad practice, unless you redo your whole directory tree.
EDIT: The install(DIRECTORY ...) shouldn't be used in this case as it was intended for literally installing a whole directory. That means copying all the files from that given directory. An example of such use would be a folder with .png files that are needed for icons in your program. Thus (out of experience) I do not recommend it's usage for the installation of headers.
I've found/created and stored two macros that help me quickly solve issues across different best practices that I come across.
I assume you wish to install the library(/ies) after you build them and then use them in another project, while preserving the specified structure. I've worked in one company where we couldn't change the folder structure, but they didn't mention anything about the install folder. The source folder resembled the one you posted. Hence after some time I got ahold of this macro and it might be useful for you too (regex might've changed across versions hence it might need some updating):
macro(install_directory_headers_macro HEADER_LIST)
foreach(HEADER ${${HEADER_LIST}})
#This gets 2 matches DIR and HEADER (folder path and header file name)
string(REGEX MATCH "(.*\/*\\*)[\/\\]" DIR ${HEADER})
install(FILES ${HEADER} DESTINATION include/${DIR})
endforeach(HEADER)
endmacro(install_directory_headers_macro)
What this macro does is to preserve the SOURCE directory structure of the include files in the install directory. Normally you would have to type it out yourself, this does it for you.
# USE:
# set(PROJ_HEADERS moduleA/moduleA.hpp moduleB/moduleB.hpp)
# install_directory_headers_macro(PROJ_HEADERS)
Bonus
Ofcourse I once had a different problem as well (this is most likely not your case) where within the same company, they wanted to build the files from source while developing it and didn't understand that they no longer can use system paths in the #include directives, unless they do some changes within the CMake files. If this is your case then this function solves this for you (so you don't have to move a finger):
function(export_headers TARGET HEADER_SOURCE_DIR HEADER_DEST_DIR)
# Put all headers that are in the source directory into EXPORT_HEADERS variable
file(GLOB_RECURSE EXPORT_HEADERS CONFIGURE_DEPENDS
RELATIVE "${HEADER_SOURCE_DIR}"
"${HEADER_SOURCE_DIR}/*.h"
)
# For each header that will be exported
foreach(HEADER ${EXPORT_HEADERS})
# Get the directory portion that needs to be created
get_filename_component(HEADER_DIRECTORY "${HEADER}" DIRECTORY)
# Create the directory
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "${HEADER_DEST_DIR}/${HEADER_DIRECTORY}"
)
if (MSVC)
# Make a hard link to the file
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND if not exist "${HEADER_DEST_DIR}/${HEADER}" \( mklink /h "${HEADER_DEST_DIR}/${HEADER}" "${HEADER_SOURCE_DIR}/${HEADER}" \)
)
else()
# Make a symbolic link to the file
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ln -sf "${HEADER_SOURCE_DIR}/${HEADER}" "${HEADER_DEST_DIR}/${HEADER}"
)
endif()
endforeach(HEADER)
endfunction()
And then you can easily...
# USE:
# add_library(libA STATIC ${LIBA_SOURCES}
# export_headers(libA ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/include/libA)
# target_include_directories(libA INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/include)
Related
I'm currently working on a larger project which is not maintained.
Explanation
It tries to use CMake but not very intuitive. Instead of including shared libs and headers from every submodule, one can set a flag in the top level CMakeList which triggers an add_subdirectory, sneaking the top level CMAKE_BUILD_DIR and installs into it. These CMakeLists use exclusively glob RECUSE to find all sources and most operation are not target based but global. Therefor the main target compiles properly. Here is a little snippet of the main CMakeList
set(MY_BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(MY_SOURCE_BASE_DIR "${MY_BASE_DIR}/myproject")
# includes
include(build/global.cmake)
#include(externalLibs/mz-cmaketools-master/global.cmake)
# configuration options
option(MOD1 "" ON)
option(MOD2 "" ON)
option(MOD3 "" OFF)
option(MOD4 "" OFF)
option(MOD5 "" ON)
option(MOD6 "" OFF)
option(MOD7 "" ON)
message("-- Building myproject unit-tests - ${ENABLE_MYPROJECT_TEST}")
set(CMAKE_ECLIPSE_MAKE_ARGUMENTS "-j4")
if(MOD1)
message(STATUS "Building viral_core + viral_recon")
add_subdirectory(${MY_BASE_DIR}/externalLibs/viral/trunk/linux)
include_directories(${MY_BASE_DIR}/externalLibs/viral/trunk/source/)
else(MOD1)
if(MOD3)
message(WARNING "Building viral_core + viral_recon")
add_subdirectory(${MY_BASE_DIR}/externalLibs/viral/trunk/linux)
include_directories(${MY_BASE_DIR}/externalLibs/viral/trunk/source/)
endif(MOD3)
endif(MOD1)
# external libraries
include(${MY_BASE_DIR}/externalLibs.cmake)
include_directories(
${MY_BASE_DIR}
${MY_SOURCE_BASE_DIR}
${MY_BASE_DIR}/externalLibs/viral/trunk/source/
)
# depending on the supported robots we have different dependencies
if( MOD1 )
set(OPT1 TRUE)
endif()
...
# collect binaries
set(LIBRARY_OUTPUT_PATH ${MY_BASE_DIR} CACHE PATH "Library output path")
set(EXECUTABLE_OUTPUT_PATH ${MY_BASE_DIR} CACHE PATH "Executable output path")
message("-- Setting executable output path: ${EXECUTABLE_OUTPUT_PATH}")
message("-- Setting library output path : ${LIBRARY_OUTPUT_PATH}")
# collect sources
file(GLOB MY
"${MY_SOURCE_BASE_DIR}/*.h"
"${MY_SOURCE_BASE_DIR}/*.cpp"
)
source_group(base FILES ${MY_BASE})#
file(GLOB MY_UTIL
"${MY_SOURCE_BASE_DIR}/util/*.h"
"${MY_SOURCE_BASE_DIR}/util/*.cpp"
)
source_group(util FILES ${MY_UTIL})
file(GLOB_RECURSE MY_KINEMATICS
"${MY_SOURCE_BASE_DIR}/kinematics/*.h"
"${MY_SOURCE_BASE_DIR}/kinematics/*.cpp"
)
source_group(kinematics FILES ${MY_KINEMATICS})
file(GLOB MY_COLLISION
"${MY_SOURCE_BASE_DIR}/collision/pqp/*.cpp"
"${MY_SOURCE_BASE_DIR}/collision/PQP*.cpp"
)
source_group(collision FILES ${MY_COLLISION})
...
add_library(MY SHARED
${MY_COLLISION}
${MY_UTIL}
${MY_KINEMATICS}
...}
)
....
In the end the project builds several libs, but does not publish required headers to use them. These libs are put into the top level of the build directory. (without an install step)
Question
Is there a possibility to make CMake to export the included header for a lib (target). To be more precisely, these headers should only lie within the source folder and below; headers from /usr/... should not be considered. Furthermore it is acceptable if the headers are merged into one single header. But from the ~1700 headers only ~40 are relevant, so a simple find RECURSE does not seem adequate to me.
I did have a look at GENERATE_EXPORT_HEADER but do not think that is what I look for. And I do not have the permission to change the project, so I want to make a patch to the SVN repository and do NOT want to make another copy of the repository, because there are around 10 different in use.
I would appreciate any hints towards a solution or strategy
This is my very first question on stackoverflow, so please be merciful :)
I hope I understood your question correctly.
I usually use the CMakePackageConfigHelpers to generate cmake configuration files for the lib, if done correctly the nice thing is that CMake sets up transitive dependencies and include directories automatically when you link against a library with a package config.
The install command can then be used to copy targets, directories, include files to the CMAKE_INSTALL_PREFIX dir, or into an archive via CPack.
After declaring my target I will usually have something along the lines of:
install(TARGETS MyLibrary
LIBRARY DESTINATION lib
)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${GENERATED_DIR}/MyLibraryConfigVersion.cmake" COMPATIBILITY SameMajorVersion
)
configure_package_config_file(
"cmake/Config.cmake.in"
"${GENERATED_DIR}/MyLibraryConfig.cmake"
INSTALL_DESTINATION "cmake"
)
install(FILES
inc/someHeader.h
inc/someHeaderB.h
DESTINATION include/MyLibrary
)
install(FILES
"${GENERATED_DIR}/MyLibraryConfig.cmake"
"${GENERATED_DIR}/MyLibraryConfigVersion.cmake"
DESTINATION "cmake"
)
Then you can set CMAKE_INSTALL_PREFIX to a directory of your choice and run make install, creating the following structure:
InstallationDir
├── cmake
│ ├── MyLibraryConfig.cmake
│ └── MyLibraryConfigVersion.cmake
├── include
│ └── MyLibrary
│ ├── someHeaderB.h
│ └── someHeader.h
└── lib
└── MyLibrary.so
Then you can use find_package in CONFIG mode to automatically set up include directories, compile options etc. when linking against MyLibrary.so.
Just a hint: The target_include_directories function is preferred to include_directories. I am not sure how well config file generation works if you do not use it. Also take a look at the following functions for more advanced control on your target: set_target_properties, target_link_libraries, target_compile_definitions
I am currently working on a C++ project using CMake as its build system.
The projects consists of several output executables, each having relatively little custom code, but leveraging a few common libraries:
programX
|
├── CMakeLists.txt (this contains the main executable targets)
|
├── Engine
│ ├── ...
│ ├── CMakeLists.txt
|
├── Utils
│ ├── third_party (this is what I added)
│ │ └── backward-cpp
│ | └ CMakeLists.txt
│ ├── ...
│ └── CMakeLists.txt
|
└── etc.
The main functionality of the project is contained inside an Engine library which is statically linked to the main executables using something like target_link_libraries(programX Engine). Many utilities are also contained in a separate Utils library.
I have added a CMake dependency to one of these project libraries (it's the backward-cpp stacktrace prettifier). That project is also built using CMake.
In the interest of modularity, I have added the backward-cpp project as a dependency to the only project library which actually uses it, Utils. I did this in order not to "pollute" the main CMakeLists.txt file with directives only pertaining to a small part of the project.
My Utils/CMakeLists.txt therefore looks like this:
SET(UTILS_HEADERS ...)
set(UTILS_OBJECTS Dummy.cpp ${UTILS_HEADERS})
# This is the new dependency!
add_subdirectory(third_party/backward-cpp)
SOURCE_GROUP("" FILES ${UTILS_HEADERS})
# 'BACKWARD_ENABLE' and 'add_backward' are needed for linking.
add_library(Utils ${UTILS_OBJECTS} ${BACKWARD_ENABLE})
add_backward(Utils)
Doing this, however, does not work, and the project ends up not linking (the symbols from the backward-cpp library are not found), unless I link the output executables to the third party library directly, in the root CMakeLists.txt file (add_backward(MainExecutableA-Z)).
I am aware that one cannot link static libraries to other static libraries, but I would be interested in knowing if there is a nice way to achieve this modularization of static libraries and their dependencies using CMake.
(Alternatively, I could always just link everything directly to the main targets, since that always works.)
Update (May 22nd 2017)
I've managed to get everything working now, with backwards-cpp being controlled 100% from the "narrowest" CMakeLists.txt file, thanks to the helpful answers I got. Here's the Utils/CMakeLists.txt file I ended up with (non-relevant parts removed):
SET(UTILS_HEADERS ...)
SET(UTILS_SOURCES ...)
# If enabled, enables sensible stack traces on Linux, complete with corresponding source
# code, where available. CUDA errors also produce complete stack traces when this is on.
# If disabled, the error messages degrade gracefully to file/line information.
OPTION(WITH_BACKWARDS_CPP "Build with backwards-cpp stack trace dumping library? (Linux-only)" TRUE)
message(STATUS "backwards-cpp-enhanced stack traces? " ${WITH_BACKWARDS_CPP})
if(WITH_BACKWARDS_CPP)
# Support 'backward-cpp,' a lean stacktrace printing library for Linux.
add_definitions(-DWITH_BACKWARDS_CPP)
add_subdirectory(third_party/backward-cpp)
endif()
SOURCE_GROUP("" FILES ${UTILS_HEADERS} ${UTILS_SOURCES})
add_library(Utils ${UTILS_HEADERS} ${UTILS_SOURCES})
# ...unrelated CUDA stuff...
if(WITH_BACKWARDS_CPP)
# Link agains libbfd to ensure backward-cpp can extract additional information from the binary,
# such as source code mappings. The '-lbfd' dependency is optional, and if it is disabled, the
# stack traces will still work, but won't show unmangled symbol names or source code snippets.
# You may need to set BACKWARD_USE_BFD to 0 in its `hpp` and `cpp` files to avoid linker errors.
target_link_libraries(Utils PUBLIC -lbfd)
target_link_libraries(Utils PUBLIC backward)
endif()
After looking inside the BackwardConfig.cmake and reading the project's README I came to the conclusion that the most easy way to link your executable with the Backward-cpp is using the add_backward(target) macro as you mentioned in your question.
The other option described under Modifying CMAKE_MODULE_PATH subtitle in the README shuld work as well but I not tested. The find_package in Config mode will search for file called <name>Config.cmake which is BackwardConfig.cmake in this case, so you don't have to write any extra CMake modules like FindBackward.cmake. As a try I would do the following:
set(UTILS_HEADERS ...)
set(UTILS_OBJECTS Dummy.cpp ${UTILS_HEADERS})
source_group("" FILES ${UTILS_HEADERS})
add_library(Utils ${UTILS_OBJECTS})
list(APPEND CMAKE_MODULE_PATH /path/to/backward-cpp)
find_package(Backward)
target_link_libraries(Utils PUBLIC Backward::Backward)
After reading the README of backward-cpp, I would try the following (only the last two lines change):
SET(UTILS_HEADERS ...)
set(UTILS_OBJECTS Dummy.cpp ${UTILS_HEADERS})
# This is the new dependency!
add_subdirectory(third_party/backward-cpp)
SOURCE_GROUP("" FILES ${UTILS_HEADERS})
add_library(Utils ${UTILS_OBJECTS})
target_link_libraries(Utils PUBLIC backward)
Note that PUBLIC in the last statement takes care of setting the include directories and link libraries when you link other targets against Utils.
I have a package called MYLIBS consisting of two libraries, lib1 and lib2, which I want to export through the configuration file for the package. The project structure is as follows:
├── Lib1
│ ├── CMakeLists.txt
│ ├── lib1-class.cpp
│ └── lib1-class.h
├── lib2
│ └── CMakeLists.txt
│ ├── lib2-class.cpp
│ ├── lib2-class.h
├── cmake
│ └── LIBSConfig.cmake.in
├── CMakeLists.txt
In lib2 I have:
add_library(lib2
STATIC
${SOURCE_FILES}
)
target_include_directories(lib2 PRIVATE /path/to/lib1)
target_link_libraries(lib2 PUBLIC lib1)
add_dependencies(lib2 lib1)
install(
TARGETS
lib2
DESTINATION
lib/MYLIBS/lib2
EXPORT
lib2Exports
)
install(
EXPORT
lib2Exports
DESTINATION
lib/MYLIBS/lib2
)
The same as lib1 except that lib1 does not have the add_dependencies() and target_include/link() as it does not have one.
In my configuration file template, I have:
#PACKAGE_INIT#
## PROJECT_LIBRARIES is filled-in during the package build. in this case : lib1,lib2
set(#PROJECT_NAME#_LIBRARIES #PROJECT_LIBRARIES#)
## The public variables to be used by the client project:
#PROJECT_NAME_INCLUDE_DIRS is all the include paths
#PROJECT_NAME_LIBRARIES is the name of all the libraries
unset(#PROJECT_NAME#_INCLUDE_DIRS)
foreach(INCLUDE_DIR ${INCLUDE_DIRS})
set_and_check(#PROJECT_NAME#_INCLUDE_DIR ${INCLUDE_DIR})
list(APPEND #PROJECT_NAME#_INCLUDE_DIRS ${#PROJECT_NAME#_INCLUDE_DIR})
endforeach()
## PACKAGE_PACKAGE_DIRNAME_include is filled-in during the package build
foreach(lib ${#PROJECT_NAME#_LIBRARIES})
list(APPEND INCLUDE_DIRS #PACKAGE_PACKAGE_DIRNAME_include#/${lib})
endforeach(lib)
# Looks up the information about the exported targets in this package
foreach(lib ${#PROJECT_NAME#_LIBRARIES})
if(NOT TARGET ${lib})
include(#PACKAGE_PACKAGE_DIRNAME_lib#/${lib}/${lib}Exports.cmake)
endif()
endforeach(lib)
So I go through the export files for libraries one by one and include them. The problem is that I have to do that in the right order, i.e. lib1 first and then lib2, otherwise I get an error when reading the configuration file by FindPackage().
I am not really sure how the transitive dependencies would work tbh. Since these libraries are include()ed from the same export file, is there a way of telling CMake about the dependencies in the configuration file or in the export file of lib2 considering that we know where the export files for the dependencies are going to be on the system?
I can see target_link_libraries() has a PUBLIC option. How am I supposed to use that? Would it be of any help?
To begin with, you can remove the add_dependencies line. See target_link_libraries and add_dependencies.
Second, you have
target_include_directories(lib2 PRIVATE /path/to/lib1)
But that should not be needed. Instead, remove it, and add this to lib1:
target_include_directories(lib1 PUBLIC /path/to/lib1)
Those are just clean-ups though.
You didn't post the error, and there is lots of other important information missing in your post, so I do some guessing.
I guess the error is something along the lines of
The following imported targets are referenced, but are missing: lib2
You export lib1 and lib2 in two separate 'export sets' - lib1Exports and lib2Exports. Putting them in one 'export set' would solve the problem and be the easiest way forward, at least in the two-target example.
I guess you know that, and you are not doing it because the scale of your build system is bigger than two targets. However, that leads directly to your problem - it means you must manage the order dependencies between 'export sets'.
This is independent of dependencies between targets. An 'export set' is a different 'unit' with an independent dependency graph. CMake doesn't help you to manage it. You have to manage the dependencies between 'export sets'. The problem is that you are not currently managing or expressing those dependencies. See below for your options regarding expressing those dependencies.
target_link_libraries(PUBLIC) does not help you. Read about it in Transitive Usage Requirements.
If you think of an analogy to preprocessor files, you might see your options. Think of lib2_private.h which does not #include lib1_private.h. A alllibs.h will need to include those two in the correct order. Because the _private headers are private, and because clients will always include alllibs.h instead, that will work. In this approach, you manage the total dependency tree in one place.
An alternative approach would be to create lib2_internal.h which contains
#include "lib1_private.h"
#include "lib2_private.h"
and lib1_internal.h which contains
#include "lib1_private.h"
In this approach, you manage dependencies close to their dependers, so you would have multiple places which specify subsets of the total dependency tree. The alllibs.h could use
#include "lib1_internal.h"
#include "lib2_internal.h"
or
#include "lib2_internal.h"
#include "lib1_internal.h"
and the order would not matter.
Your configuration file with the loop is alllibs.h - it is the only file clients include. Can you manage the order entirely there? Yes, if you can manage the order within the #PROJECT_NAME#_LIBRARIES variable. By the way, you should call that #PROJECT_NAME#_EXPORT_SETS probably. If you don't see why, have another look at what I said above about it being a different 'unit'.
You didn't give much information, but I guess you are populating that with multiple
list(APPEND MYPROJ_EXPORT_SETS fooExports)
calls, perhaps in some macro. So the order is not easily maintainable, as it would be as a single set() call.
So, your options to express 'export set' dependencies are:
Manage them in the configuration file - replace the loop with a hardcoded ordered list
Add more variables to express dependencies of export sets wherever you populate the MYPROJ_EXPORT_SETS variable, and replace the loop in your configuration file with something more complex that takes those dependencies into account.
Same as (2), but generate intermediate files and don't care about the include order within the configuration file.
(1) probably makes most sense, but you might also have to step back and think harder about the abstractions/wrappers you're creating which led you here.
How do I set up CMake to recursively scan a given directory and determine the list of source files?
My project is a shared library. I have a folder structure similar to this:
/
src/ # Source files in an arbitrary tree
include/ # Headers, tree mirrors that of the src/ folder
examples/ # Executable code examples that link against the library
CMakeLists.txt
I want CMake to recursively scan src and include and determine the list of source and header files in my project, regardless of the directory structure. I also want to avoid:
Polluting the src/ and include/ directories with endless CMakeLists.txt files
Having to change and adapt the scripts every time I change my folder structure
It is fine for each example to have their own build script, however.
CMake provides the following command for recursive files globing:
file(GLOB_RECURSE variable [RELATIVE path]
[FOLLOW_SYMLINKS] [globbing expressions]...)
Command documentation: http://www.cmake.org/cmake/help/v2.8.8/cmake.html#command:file
What's a good directory structure for larger C++ projects using Makefile ?
This is how my directory structure looks at the moment:
lib/ (class implementations *.cpp)
include/ (class definitions *.h)
tests/ (main.cpp for quick tests)
Now, I'm not sure how my Makefile should look like... it doesn't seem to work when .cpp files and .h files aren't in the same directory. Could anyone point me to a common directory structure with an accompanying Makefile so that I don't reinvent the wheel ?
Separating the .cpp of the .h file is not always a good solution. Generally I separate both of them when it is used as a library (public header in include and private header with the source code).
If it is a library, this structure is ok.
lib/ (class implementations *.cpp .h)
include/ (class definitions *.h) <- Only those to be installed in your system
tests/ (main.cpp for quick tests)
doc/ (doxygen or any kind of documentation)
If it is a application
src/ (source for the application)
lib/ (source for the application library *.cpp *.hpp)
include/ (interface for the library *.h)
tests/ (main.cpp for quick tests) <- use cppunit for this part
doc/ (doxygen or any kind of documentation)
Use the flag -I$(PROJECT_BASE)/include to specify the include path for the compilation
If it is a big project, it can be good to use tool like autoconf/automake or cmake to build everything. It will ease the development.
For those who find this question after 2020, an alternative modern and reasoned vision of "Canonical Project Structure" for C++ has been presented by Boris Kolpackov: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1204r0.html
Briefly - no include/ and src/ split. All headers, sources, modules and unit tests go into one directory. Implementation details may be separated from public API by moving to <name>/<name>/details/ subdirectory.
<name>/
├── <name>/
│ ├── headers...
│ ├── sources...
│ ├── modules...
│ └── unit tests...
└── tests/
├── functional_test1/
├── functional_test2/
├── integration_test1/
├── integration_test2/
└── ...
For example:
bestlib/
├── bestlib/
│ ├── foo.h
│ ├── foo.cpp
│ ├── foo.test.cpp
│ ├── bar.h
│ ├── bar.cpp
│ └── bar.test.cpp
└── tests/
├── functional_test1/
└── integration_test1/
If you have many source files, it may also be a good idea to further subdivide your source directory. For instance, one subdirectory for the core functionality of your application, one for the GUI, etc.
src/core
src/database
src/effects
src/gui
...
Doing so also forces you to avoid unneeded relationships between your "modules", which is a prerequisite to nice and reusable code.
There is no one specific or required directory structure.
You can set it up anyway you like. Your problem is simple to solve. Just instruct Makefile to look into subdirectories or put compiled objects into subdirectories instead of using just current directory.
You would just use in Makefile paths:
%.o : %.cpp
replace with
bin/%.o : %.cpp
So it will check if binary file in directory bin exists and so on, you can apply the same to locations where files are compiled.
There are ways to add/remove/modify paths of source and object files.
Have a look at gnu make manual, specifically section 8.3 Functions for File Names,and the one before that 8.2 Functions for String Substitution and Analysis.
You can do stuff like:
get a list of objects from list of source files in current directory:
OBJ = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
Output:
Application.o Market.o ordermatch.o
If binary objects are in subdirectory bin but source code is in current directory you can apply prefix bin to generated object files:
OBJ = $(addprefix bin/,$(patsubst %.cpp, %.o, $(wildcard *.cpp)))
Output:
bin/Application.o bin/Market.o bin/ordermatch.o
And so on.
This is an old question. But you can consider the Pitchfork Project as a general guide.
https://github.com/vector-of-bool/pitchfork for the project.
Some Documentation here
There is no "good directory structure". Pick a structure you're comfortable with and stick to it. Some like placing source files (headers and implementation files) in a src/ directory, so the root directory of the project has nothing but a makefile, a readme and little else. Some like placing helper libraries under a lib/ directory, unittests under test/ or src/test/, documentation under doc/ etc.
I have yet to hear of anyone splitting header files and implementation files into two distinct directories though. Personally I don't like splitting files into directories much. I usually place all my source in a single directory and all the documentation in another directory. If I rely on good search tools anyway, there's no need for a complex directory structure.
make can deal with the sort of structure where the makefile resides in a different directory than the source. The only thing is that it will invoke the rules from the directory of the makefile -- compilers usually have no problem compiling source that is in some subdirectory. You don't have to specify relative paths in your #includes; just specify the include path with compiler flags (gcc's -I flag etc).
If you haven't seen it before read Recursive Make Considered Harmful.
Short, short version: Though very common the recursive make idiom is less than optimal and gets ever worse as projects grow larger and more complicated. An alternative is presented.
Related link: What is your experience with non-recursive make?