I am currently working on a project, that looks like this:
root folder
|---plugin manager
| |---plugin_manager.cpp
| |---plugin_interface.hpp
|
|---libraries
|
|---Plugins
| |
| |---Plugin1
| | |---Plugin1.cpp
| | |---Plugin1.hpp
| |---Plugin2
| | |---Plugin2.cpp
| | |---Plugin2.hpp
I am compiling a .so for each plug-in and then I "load" it with the plugin_manager. This works fine. I even created a simple makefile, which is able to compile a .so. Here are my make and config files:
configure.ac
AC_INIT(My Project, 0.1, my#email, myproject)
AC_PREREQ(2.68)
AC_COPYRIGHT(GNU General Public License)
AM_CONFIG_HEADER([config.h])
AC_CONFIG_MACRO_DIR([m4])
AM_PROG_LIBTOOL
AC_PROG_INSTALL
AC_PROG_CXX
AM_INIT_AUTOMAKE([1.9 foreign])
AC_CONFIG_FILES(Makefile)
AC_ENABLE_SHARED
AC_DISABLE_STATIC
LT_INIT
AC_OUTPUT
Makefile.am
ACLOCAL_AMFLAGS = -I m4
#Generating libtest.so
lib_LTLIBRARIES = libtest.la
#here you can list your source files
libtest_la_SOURCES = Plugin1.cpp
libtest_la_LDFLAGS = -module -avoid-version -export-dynamic
However, this make file is not that user-friendly, since I have to put it manually in each plug-in folder and also change its source files. That is why I want to create another one, which basically by typing make creates an executable in the plugin manager folder, as well as a .so in each plug-in folder. I have been reading for the last couple of days about autotools and tried implementing something similar to what the guys here suggested, but it didn't work. So I hope that there is someone here, who has experience with such makefiles and can give me a tip on how to solve my problem.
Automake has limitations even with wildcards (http://www.gnu.org/software/automake/manual/html_node/Wildcards.html).
I do not thing that to do what you want is possible without using a bash script to generate your Makefile.am.
However, if using CMake is not a problem for you.
You should be able to do it with something like
FILE(GLOB dir_list "${CMAKE_CURRENT_SOURCE_DIR}/Plugins/*")
FOREACH(dir_entry dir_list)
FILE(GLOB file_src "${dir_entry}/*.cpp"
add_library(plugin_${dir_entry} ${file_src})
ENDFOREACH(dir_entry dir_list)
Related
I'm working on some basic OpenGL program and want to use CMake for building it.
There are couple of dependencies like glfw, glad, imgui etc...
Currently I have it in a very draft state where everything is just under the sources directory:
./
|____CMakeLists.txt
|____build/
|____include/
| |____KHR/
| |____GLFW/
| |____...
|____lib/
| |____libglfw3.a
| |____...
|____src/
| |____main.cpp
| |____...
| |____vendor/
| | |____imgui/
| | |____glad/
| | |____stb_image/
My CMake config is something like this:
include_directories(${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src/vendor)
add_executable(${PROJECT_NAME}
src/main.cpp
src/vendor/glad/glad.c src/vendor/glad/glad.h
src/vendor/imgui/...
...
)
target_link_libraries(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/lib/libglfw3.a)
It all works, but now I want to bring some structure into it.
Mainly I want to have only my code under src.
I hope I'm not going into "XY problem" but I believe my file structure should be like:
./
|____CMakeLists.txt
|____build/
|____include/
|____lib/
|____glad/
| |____CMakeLists.txt
| |____...
|____imgui/
| |____CMakeLists.txt
| |____...
|____...
|____myproject/
| |____CMakeLists.txt
| |____src/
| | |____main.cpp
| | |____...
So that I'll have separate CMake configs for building glad, imgui etc., and then using them to build myproject.
Unfortunately, I'm struggling with understanding CMake documentation. Should I use INTERFACE targets for dependencies? Or how can I tell CMake that imgui must use specific GLFW location?
My main aim is to build myproject. For that I have to also build dependencies. Some dependencies are using other dependencies which I use. For example: I use GLFW and imgui also uses it. Ideally I'd like to be able to have only one place for that. In my case I have it under include and lib in the root of file structure.
Can anyone please share some ideas what could be the CMake config for such case?
What are the best practices?
Language server (clangd) says he can't find lib.h when I trying to include header in lib_gtests.cpp : #include "lib.h".
But when I compile everything is OK and lib_gtests can find a header file.
I may miss something in CMake or I should use an IDE because they are more "smart" and are able to find these pre-build dependencies
project
|
|-------> src
| |----> main.cpp
| |----> lib
| |----> lib.cpp
| |----> lib.h
|
|
|-------> tests
| |----> lib
| |----> lib_gtests.cpp
|
|
|---->CMakeLists.txt
CMakeLists.txt
add_executable(unit_tests
tests/lib/lib_gtests.cpp
)
target_link_libraries(unit_tests PRIVATE lib)
target_include_directories(unit_tests PRIVATE ${CMAKE_SOURCE_DIR}/src/lib)
sorry for a dumb question, I'm new to C++ and CMake
and sorry for my English in advance
and could I ask for an advice for sources on CMake (not the official docs, they're scary)
use an IDE (it'll make all these included directories on compile stage visible for a language server by itself, I guess this is why everything works fine for me)
or, if you really want to use some text editor with a language server (for instance NeoVim, as I do. Actually, it's such a pain in the butt but I like this) use ccls as a language server and tell CMake to create compile_commands.json file and create a link to this file in your project directory.
cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=YES
ln -s build/compile_commands .
How to compile and link third party libraries with automake?
My file structure is:
program/
|
+--src/
| |
| +--Makefile.am
| +--main.cpp
|
+--lib/
| |
| +--Makefile.am
| +--library.cpp
|
+--Makefile.am
+--configure.ac
+--README
Contents of automake files are pretty generic:
# src/Makefile.am
bin_PROGRAMS = program
program_SOURCES = main.cpp
# Makefile.am
SUBDIRS = src lib
dist_doc_DATA = README
# configure.ac
AC_INIT([program], [1.0])
AM_INIT_AUTOMAKE([-Wall])
AC_PROG_CXX
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile src/Makefile lib/Makefile])
AC_OUTPUT
What should be the contents of lib/Makefile.am?
(Not sure why you said "third-party" when you appear to have control of the library code yourself... For more info related to creating and working with libraries using Automake, I refer you to the GNU Automake manual's section on libraries)
lib/Makefile.am
lib_LIBRARIES = libYOURLIB.a
libYOURLIB_a_SOURCES = library.cpp
You can use noinst_lib_LIBRARIES if you don't want to install the library itself. Note that I'm assuming you want to build a static library only. See the Building A Shared Library section of the GNU Automake manual for integrating with Libtool to produce a shared library. You can do it manually of course, but it's a lot easier with Libtool as it takes care of various platform differences.
To link your library to program, you'd add the following lines insrc/Makefile.am:
program_DEPENDENCIES = $(top_builddir)/lib/libYOURLIB.a
program_LDADD = $(top_builddir)/lib/libYOURLIB.a
The _DEPENDENCIES line simply tells Automake that program relies on lib/libYOURLIB.a being built first, and the _LDADD line simply adds the library to the linker command.
The above assumes that you have a rule to build the library already. Since you're using SUBDIRS, you received a "no rule to make target XXXXXX" build failure, which indicates that you don't (at least from the perspective of the Makefile in the src subdirectory). To remedy this, you can try the following in src/Makefile.am (taken from "Re: library dependency" on the GNU Automake mailing list archives):
FORCE:
$(top_builddir)/lib/libYOURLIB.a: FORCE
<TAB>(cd $(top_builddir)/lib && $(MAKE) $(AM_MAKEFLAGS) libYOURLIB.a)
You can also simply make lib a subdirectory of src as your comment indicated of course and make it simpler.
Alternatively, you can stop using a recursive build setup and use what is perhaps a simpler non-recursive build setup. See GNU Automake Manual ยง7.3: An Alternative Approach to Subdirectories and Non-recursive Automake for some information on that, but the general idea would be to alter things to allow for :
configure.ac
AM_INIT_AUTOMAKE([-Wall subdir-objects])
...
AC_CONFIG_FILES([Makefile])
Makefile.am
# Instead of using the SUBDIRS variable.
include src/Makefile.am.inc
include lib/Makefile.am.inc
dist_doc_DATA = README
lib/Makefile.am renamed to lib/Makefile.am.inc
# Full path relative to the top directory.
lib_LIBRARIES = lib/libYOURLIB.a
lib_libYOURLIB_a_SOURCES = lib/library.cpp
src/Makefile.am renamed to src/Makefile.am.inc
# Full path relative to the top directory.
bin_PROGRAMS = bin/program
bin_program_SOURCES = src/main.cpp
bin_program_DEPENDENCIES = lib/libYOURLIB.a
bin_program_LDADD = lib/libYOURLIB.a
Renaming the files is optional (you could always just include src/Makefile.am), but it helps to denote that it isn't meant to be a standalone Automake source file.
Also, supposing that lib/library.cpp and src/main.cpp both #include "library.hpp", and it's in another directory, you might also want to use AM_CPPFLAGS = -I $(top_srcdir)/include for all files or obj_program_CPPFLAGS = -I include for all source files that are used in building bin/program, assuming library.hpp is in program/include. I'm not sure if $(top_srcdir) is right when another project includes your entire program source directory in its own SUBDIRS variable, but $(srcdir) will always refer to the top-level program directory in the case of a non-recursive automake, making it perhaps more useful in larger projects that include this package as a component.
I'm trying to find a way to build a big modular C++ project with CMake.
The structure of the project is the following:
--project_root
--src
--folder_1
--source_1.h
--source_1.cc
--test_source_1.cc // file containing a main with unit tests
--folder_2
--source_2.h
--source_2.cc
--test_source_2.cc // file containing a main with unit tests
--folder_3
...
And so on.
Each folder represent a project module and each module might depend on other modules, so for example source_1.h may include source_2.h.
Every module folder may also contains a test file so the whole project will have multiple executables.
How can I build the whole project with CMake? How should I write my CMakeLists.txt file?
Thank you a lot.
There are many, many examples out there of how to structure CMake projects for C++, many of which are referenced by the tutorial #user2485710 suggested in his comment, so I'm not going to go super in-depth here, but I'll at least give you a good starting point based on the way you want to lay out you folder structure.
The nice thing about CMake is that it can essentially do a tree-decent using the add_subdirectory command. This lets us easily divide up our CMake code to only do what is required at any specific directory level. In otherwords, each CMakeLists.txt file should only do the minimal amount of work needed to properly set up things at the current depth in the directory tree. In you example, your CMake tree might look like this:
--project_root
--src
--CMakeLists.txt
--folder_1
--CMakeLists.txt
--source_1.h
--source_1.cc
--test_source_1.cc // file containing a main with unit tests
--folder_2
--CMakeLists.txt
--source_2.h
--source_2.cc
--test_source_2.cc // file containing a main with unit tests
...
In src/CMakeLists.txt you do all of your project-level initialization, I.E. find_package, setting up your include-path, etc. Then you simply add the following at the end:
add_subdirectory(folder_1)
add_subdirectory(folder_2)
...
This tells CMake that it should look in those folders for additional stuff to do. Now in src/folder_1/CMakeLists.txt, we do the actual work of whatever combination of add_executable and add_library you need to properly build source_1.cc and test_source_1.cc, and likewise in src/folder_2/CMakeLists.txt for source_2.cc, etc.
The other nice thing is that any CMake variables you set higher up the tree are propagated down through add_subdirectory. So, for example, in src/CMakeLists.txt you can check for some sort of 'build unit-test' flag and set the CMake variable there, and then all you have to do in the other CMakeLists.txt files is check for that variable. This can also be super useful to do if you have a project where CMake is dynamically generating header files for you based on checking environment variables for path-names and the like.
If the structure of the project is well-regulated, you could write custom macros or function of cmake to define the modules and their dependencies.
The cmake scripts in OpenCV project is a good reference:
/libs/opencv-2.4.8/sources/
|+cmake/
|+doc/
|~modules/
| |+core/
| | |+doc/
| | |+include/
| | |+perf/
| | |+src/
| | |+test/
| | `-CMakeLists.txt
| |~imgproc/
| | |+doc/
| | |+include/
| | |+perf/
| | |+src/
| | |+test/
| | `-CMakeLists.txt
| |+ml/
| |+...
| |-CMakeLists.txt
|-CMakeLists.txt
root/modules/imgproc/CMakeLists.txt
set(the_description "Image Processing")
ocv_define_module(imgproc opencv_core)
You will need a CMakeLists.txt in each folder where building will occur.
project() is used to set the name of your overall project.
add_subdirectory() is used to command the configuration to process the CMakeLists.txt in that directory.
add_executable() is used to create an executable from included sources.
add_library() is used to create a static or dynamic library that can be added to executables or libraries as a dependency.
Using a build script (.bat, .cmd, or .sh) will allow you to automate some of the cmake process, such as setting up an out-of-source configuration or build.
You should look up the documentation for these commands on the cmake website, https://cmake.org/cmake/help/latest/
When I move some subdirectory away from project managed by "./configure" and all that things, it tries to get to some "../../configure.ac" and other things and is not easily buildable.
How to extract part of such project and make it independent?
There is two ways to deal with this, create a separate auto-tools build process or do away with the auto-tools and hand code or make a new Makefile.
myprojectfoo
|
+-- src
|
+-- man
|
+-- messages
|
+-- lib
|
+-- include
|
+-- others
Have a look at the illustration above, for a fictitious project called myprojectfoo and is using auto-tools to build a binary called foo. The top-level directory i.e. myprojectfoo will have configure.ac, Makefile.am and Makefile.in, in the subdirectories there would be at least Makefile.am and Makefile.in. The auto-tools will create and execute the make commands to build the project.
Now, from what I'm understanding in what you are trying to do:
myprojectfoo
| \ /
+-- sXc
| / \
+-- man
|
+-- messages
|
+-- lib
| \ /
+-- incXude
| / \
+-- others
You want to take out the src subdirectory and it's include's also. Then in that case, it would be easier to create a separate Makefile (read - no auto-tools) build.. in that case, it would be easier.
The best way I can think of it is, you will have to make that decision ultimately, how big is the subset of the project's sources you want to extract, once you go ahead with that, remove all references to Makefile.am, Makefile.in... and borrow an existing simple Makefile template to build it and invoke it like this
make -f MyMakefile
OR
If you want to build a separate project using that subset using auto-tools:
Create a bare-bones Makefile.am as shown below.
Create a bare-bones configure.ac as shown below...
Run autoscan on the source to pick out the dependencies, add the results of the output file 'configure.scan' to the configure.ac
Run automake (Do this once!)
Run autoconf then. It may complain about missing files such as INSTALL, COPYING etc
Then any subsequent changes to configure.ac, run autoreconf after that, which will execute automake, autoconf, and other supporting auto-tools programs.
Taking a sample of the Makefile.am for Linux...
SUBDIRS = src include
ACLOCAL_AMFLAGS = -I m4
Taking a sample of the configure.ac for Linux...
AC_PREREQ(2.63)
AC_INIT([mysubsetprojectfoo], [0.1a], [foo#bar.baz])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([-Wall -Werror])
AM_GNU_GETTEXT_VERSION([0.17])
AM_GNU_GETTEXT([external])
AM_CFLAGS=
# Checks for programs.
AC_HEADER_STDC
AC_PROG_CC
AC_ARG_ENABLE([debug],
[ --enable-debug Turn on debugging],
[case "${enableval}" in
yes) debug=true ;;
no) debug=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;;
esac],[debug=false])
AM_CONDITIONAL([DEBUG], [test x$debug = xtrue])
# Checks for libraries.
AC_CHECK_LIB([mylib], [mylib_function], [:])
if test "$mylib" = :; then
AC_MSG_ERROR([MyLib is missing.\
This can be downloaded from 'http://www.foo.baz'])
fi
AC_CONFIG_HEADERS([config.h])
# Checks for header files.
# FROM running 'autoscan' on the source directory
AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h locale.h netinet/in.h stdlib.h string.h sys/ioctl.h sys/socket.h syslog.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_INLINE
AC_C_CONST
AC_TYPE_SIGNAL
AC_TYPE_PID_T
AC_TYPE_UID_T
AC_TYPE_SIZE_T
# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_CHECK_FUNCS([atexit inet_ntoa memset regcomp socket strdup strerror])
AC_CONFIG_FILES([Makefile src/Makefile include/Makefile])
AC_OUTPUT
The commands for the auto-tools, is top of my head and I may have missed something..feel free to point out by placing a comment on this at the bottom of this post and it will be amended accordingly.