cmake is a
brand new building tool for software projects. It aims at
replacing the old fashioned autotools.
cmake is
open source and is well described here.
Among
the
numerous
provided
features,
we
can
list
the
following:
The project called PROJECT1 is composed with the following sub-tree (the files can be downloaded from it):
project1 /\ / \ / \ main.c simple |
The project generates one target: an executable called simple. All the objects are stored into the top level directory.
The following sub-tree shows the files that have been added to build the project.
project1 / | \ / | \ / | \ / | \ main.c simple CMakeLists.txt |
Once the cmake files are setup, launch cmake to generate the build environment:
$ cd project1 $ cmake . -- The C compiler identification is GNU -- Check for working C compiler: /usr/bin/gcc -- Check for working C compiler: /usr/bin/gcc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Configuring done -- Generating done -- Build files have been written to: .../project1 |
Then, the makefiles are ready to trigger a build with:
$ make [100%] Building C object CMakeFiles/simple.dir/main.c.o Linking C executable simple [100%] Built target simple |
After then, it is possible to clean-up anything generated by the environment with:
$ make clean |
The project1 directory is the top directory of the project. This is the place where we launch the cmake command.
This is the top CMakeLists.txt
of the project.
We define the minimum version of cmake
that we support for this project through the directive CMAKE_MINIMUM_REQUIRED.
We identify the project as well as the programming language with the PROJECT directive.
We define the flags that will be passed as arguments to the compiler
through the ADD_DEFINITIONS
directive. It is optional to do it but the default flags passed to the
compiler are not sufficiently severe to check and report the warnings
and bugs.
We specify the target executable simple
with
the ADD_EXECUTABLE
directive.
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(project1 C) ADD_DEFINITIONS(-g -O2 -fsigned-char -freg-struct-return -Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Winline -Werror) ADD_EXECUTABLE(simple main.c) |
The project called PROJECT2 is composed with the following sub-tree (the source files can be downloaded from it):
project2 /\ / \ / \ main.c crypto |
The project generates one target: an executable called crypto. All the objects are stored into the top level directory. The executable needs the standard library libcrypt.so.
The following sub-tree shows the files that have been added to build the project.
project2 / | \ / | \ / | \ / | \ main.c crypto CMakeLists.txt |
Once the cmake files are setup, launch cmake to generate the build environment:
$ cd project2 $ cmake . -- The C compiler identification is GNU -- Check for working C compiler: /usr/bin/gcc -- Check for working C compiler: /usr/bin/gcc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Configuring done -- Generating done -- Build files have been written to: .../project2 |
Then, the makefiles are ready to trigger a build with:
$ make [100%] Building C object CMakeFiles/crypto.dir/main.c.o Linking C executable crypto [100%] Built target crypto
After then, it is possible to clean-up anything generated by the cmake environment with:
$ make clean |
The project2 directory is the top directory of the project. This is the place where we launch the cmake command.
This is the top CMakeLists.txt of the project.
We define the minimum version of cmake that we support for this
project through the directive CMAKE_MINIMUM_REQUIRED.
We identify the project as well as the programming language with the PROJECTdirective.
We define the flags that will be passed as arguments to the compiler through the ADD_DEFINITIONS directive. It is optional to do it but the default flags passed to the
compiler are not sufficiently severe to check and report the warnings
and bugs.
We specify the target executable crypto
with the ADD_EXECUTABLE directive.
As crypto needs the libcrypt.so
library, we specify it with the directive TARGET_LINK_LIBRARIES.
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(project2 C) ADD_DEFINITIONS(-g -O2 -fsigned-char -freg-struct-return -Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Winline -Werror) ADD_EXECUTABLE(crypto main.c) TARGET_LINK_LIBRARIES(crypto crypt) |
The project called ROOF is composed with the following sub-tree:
roof / | \ \ / | \ \ / | \ \ / | \ \ / | \ \ / | \ \ / | \ \ / | \ \ lib client include bin | | | | | | | | roof.c main.c roof.h main.o roof_p.h roof.o roof libroof.so |
The project generates two targets: a shared library called libroof.so and an
executable called roof.
All the objects are stored into the sub-directory bin.
The following sub-tree shows the files that have been added to build the project.
roof / | \ \ \ / | \ \ \ / | \ \ \ / | \ \ \ / | \ \ \ / | \ \ \ / | \ \ \ / | \ \ \ lib client include bin CMakeLists.txt | | | | | | | | roof.c main.c roof.h main.o roof_p.h CMakeLists.txt roof.o CMakeLists.txt roof libroof.so |
Once the cmake files are setup, launch cmake to generate the build environment:
$ cd roof $ cmake . -- Configuring done -- Generating done -- Build files have been written to: .../roof |
Then, the makefiles are ready to trigger a build with:
$ make [ 50%] Building C object bin/CMakeFiles/roof.dir/roof.o Linking C shared library libroof.so [ 50%] Built target roof [100%] Building C object bin/CMakeFiles/main.dir/main.o Linking C executable roof [100%] Built target main |
After then, it is possible to clean-up anything generated by the cmake environment with:
$ make clean |
The directory roof is the top directory of the project. This is the place where we launch the cmake command.
This is the top CMakeLists.txt
of the project.
We define the minimum version of cmake
that we support for this project through the directive CMAKE_MINIMUM_REQUIRED.
We identify the project as well as the programming language with the PROJECT directive.
We specify the directories where are located the include files (include and lib) with the INCLUDE_DIRECTORIES
directive.
We define the flags that will be passed as arguments to the compiler
through the ADD_DEFINITIONS
directive. It is optional to do it but the default flags passed to the
compiler are not sufficiently severe to check and report the warnings
and bugs.
We specify the list of sub-directories where are located the sources to
compile (lib
and client)
along with the target binary directory where are going the object files
(bin) with
the ADD_SUBDIRECTORY
directive.
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(roof C) INCLUDE_DIRECTORIES(include lib) ADD_DEFINITIONS(-g -O2 -fsigned-char -freg-struct-return -Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Winline -Werror) ADD_SUBDIRECTORY(lib bin) ADD_SUBDIRECTORY(client bin) |
The directory lib contains all the files to make the library libroof.so.
We assign a variable called roof_lib_src
with the list of source files which will be used to build the shared
library. There is actually only one file called roof.c. This is
done with the SET
directive.
Then we define the shared library to build through the directive ADD_LIBRARY. This
directive is passed the name of the library (roof) to build libroof.so, the SHARED keyword to specify
that it is a shared library and the list of source files which are part
of the library with the variable roof_lib_src.
SET(roof_lib_src roof.c) ADD_LIBRARY(roof SHARED ${roof_lib_src}) |
The directory client contains the files to make the executable roof.
We first define the target executable with ADD_EXECUTABLE
directive.
We first assign a variable called roof_client_src
with the list of source files which will be used to build the
executable. There is actually only one file called main.c. This is
done with the SET
directive.
We define the dependency of the executable called roof with the libroof.so through
the TARGET_LINK_LIBRARIES
directive. There is
a problem here as we would like to generate an executable called
roof and a library called libroof.so.
Normally, the directive should be written as:
ADD_EXECUTABLE(roof) TARGET_LINK_LIBRARIES(roof roof) |
But cmake complains saying:
CMake Error: Attempt to add link target roof of type: EXECUTABLE to target roof. You can only link to STATIC or SHARED libraries. |
In fact, cmake gets confused because it has the impression that we want to build roof with itself. Hence the use of an intermediate name main in the directives TARGET_LINK_LIBRARIES and ADD_EXECUTABLE. Then, we tell cmake to rename the generated main executable into roof thanks to the directive SET_TARGET_PROPERTIES.
SET(roof_client_src main.c) ADD_EXECUTABLE(main ${roof_client_src}) TARGET_LINK_LIBRARIES(main roof) SET_TARGET_PROPERTIES(main PROPERTIES OUTPUT_NAME roof) |
The project called PROJECT4
builds an executable called pdip
and a set of Linux manuals compressed with gzip tool.
The project is spreaded in the following sub-tree (the files can be downloaded from it):
project4 | | pdip.c pdip_en.1 pdip_fr.1 |
pdip.c is the source of the program and pdip_en.1
and pdip_fr.1
are respectively the english and french manuals.
The following sub-tree shows the files that have been added to build
the project.
project4 | | pdip.c pdip_en.1 pdip_fr.1 FindGZIP.cmake CMakeLists.txt pdip_chown.cmake |
To generate the build environment:
$ cd project4 -- The C compiler identification is GNU -- Check for working C compiler: /usr/bin/gcc -- Check for working C compiler: /usr/bin/gcc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Configuring done -- Generating done -- Build files have been written to: .../project4 |
To trigger the build:
$ make [ 33%] Building pdip_fr.1.gz [ 66%] Building pdip_en.1.gz Scanning dependencies of target pdip [100%] Building C object CMakeFiles/pdip.dir/pdip.c.o Linking C executable pdip [100%] Built target pdip |
To trigger the installation of the software:
$ make install |
After then, it is possible to clean-up anything generated by the cmake environment with:
$ make clean |
As the project needs to install the manuals in compressed format, we
use the directive FIND_PROGRAM
to check the presence of the gzip
tool (specified after NAMES
keyword). The directive is passed the list of directories to find into (/bin, /usr/bin and /usr/local/bin).
The result of the command goes into the variable GZIP_TOOL passed as
first parameter of the directive. If gzip
is found, its
path is stored into the variable GZIP_TOOL.
If
it
is
not
found,
GZIP_TOOL
is assigned with GZIP_TOOL-NOTFOUND.
The result of the search is checked with the IF
directive which returns true if the variable's value is not empty, 0,
N, NO, OFF,
FALSE, NOTFOUND or
<variable>-NOTFOUND. If
the
test is false, a message is displayed thanks to the MESSAGE directive
with a weight set to FATAL_ERROR
to stop any future processing.
FIND_PROGRAM(GZIP_TOOL NAMES gzip PATHS /bin /usr/bin /usr/local/bin) IF(NOT GZIP_TOOL) MESSAGE(FATAL_ERROR "Unable to find 'gzip' program") ENDIF(NOT GZIP_TOOL) |
This project contains only one CMakeLists.txt
file.
We define the minimum version of cmake
that we support for this project through the directive CMAKE_MINIMUM_REQUIRED.
The project's name project4
as well as the used programming language (C) are declared
with the directive PROJECT.
Then we include the file FindGZIP.cmake
to trigger the search of the gzip
tool (INCLUDE directive).
If gzip
tool has been found, its pathname is stored in the variable GZIP_TOOL.
Three variables are set with the SET
directive:
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(project4 C) # Search for gzip program INCLUDE (FindGZIP.cmake) SET(pdip_src pdip.c) SET(pdip_exe pdip) SET(pdip_man_src pdip_en.1 pdip_fr.1) SET(pdip_man_gz pdip_en.1.gz pdip_fr.1.gz) # Compression of the manuals FOREACH(man ${pdip_man_src}) ADD_CUSTOM_COMMAND(OUTPUT ${man}.gz COMMAND ${GZIP_TOOL} -c ${man} > ${man}.gz DEPENDS ${man} COMMENT "Building ${man}.gz") ENDFOREACH(man) # Compilation options passed to the compiler ADD_DEFINITIONS(-g -O2 -fsigned-char -freg-struct-return -Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Winline -Werror) # Build of the program ADD_EXECUTABLE(${pdip_exe} ${pdip_src} ${pdip_man_gz}) # Installation of the program INSTALL(TARGETS pdip DESTINATION "bin" PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) # Installation of the manuals INSTALL(FILES pdip_fr.1.gz DESTINATION "share/man/fr/man1" PERMISSIONS OWNER_READ GROUP_READ WORLD_READ RENAME pdip.1.gz) INSTALL(FILES pdip_en.1.gz DESTINATION "share/man/man1" PERMISSIONS OWNER_READ GROUP_READ WORLD_READ RENAME pdip.1.gz) # Script to be executed at installation time (kind of post-intallation script) to # change the right accesses on the installed files INSTALL(SCRIPT pdip_chown.cmake) |
# Copy the files to the destination directory EXECUTE_PROCESS(COMMAND chown root ${CMAKE_INSTALL_PREFIX}/bin/pdip COMMAND chgrp root ${CMAKE_INSTALL_PREFIX}/bin/pdip COMMAND chown root ${CMAKE_INSTALL_PREFIX}/share/man/fr/man1/pdip.1.gz COMMAND chgrp root ${CMAKE_INSTALL_PREFIX}/share/man/fr/man1/pdip.1.gz COMMAND chown root ${CMAKE_INSTALL_PREFIX}/share/man/man1/pdip.1.gz COMMAND chgrp root ${CMAKE_INSTALL_PREFIX}/share/man/man1/pdip.1.gz) |
The project called ROOF is composed with the following sub-tree:
roof>
/ | \ \
/ | \ \
/ | \ \
/ | \ \
/ | \ \
/ | \ \
/ | \ \
/ | \ \
lib client include man
| | | |
| | | |
roof.c main.c roof.h roof.1
roof_p.h roof.3
...
roof.7
|
The project generates the following targets:
The following sub-tree shows the files that have been added to build the project.
roof>
/ | \ \ \
/ | \ \ \
/ | \ \ \
/ | \ \ \
/ | \ \ \
/ | \ \ \
/ | \ \ \
/ | \ \ \
lib client include man CMakeLists.txt
| | | |
| | | |
roof.c main.c roof.h roof.1
roof_p.h CMakeLists.txt CMakeLists.txt roof.3
CMakeLists.txt ...
roof.7
CMakeLists.txt
FindGZIP.cmake
|
Once the cmake files are setup, launch cmake to generate the build environment (with /tmp as target installation directory instead of the default /usr/local):
$ cd roof $ cmake . -DCMAKE_INSTALL_PREFIX=/tmp -- Configuring done -- Generating done -- Build files have been written to: .../roof |
Then, the makefiles are ready to trigger a build with:
$ make [ 50%] Building C object bin/CMakeFiles/roof.dir/roof.o Linking C shared library libroof.so [ 50%] Built target roof [100%] Building C object bin/CMakeFiles/main.dir/main.o Linking C executable roof [100%] Built target main |
To install the files in /tmp, just invoke:
$ make install [ 3%] Built target roof [ 7%] Built target main [100%] Built target man Install the project... -- Install configuration: "" -- Install configuration: "" -- Installing /tmp/lib/libroof.so.1.0.0 -- Install configuration: "" -- Installing /tmp/bin/roof -- Install configuration: "" -- Installing /tmp/share/man/man1/roof.1.gz -- Installing /tmp/share/man/man3/roof_cwd.3.gz -- Installing /tmp/share/man/man3/roof_login.3.gz ... |
After then, it is possible to clean-up anything generated by the cmake environment with:
$ make clean |
The directory roof is the top directory of the project. This is the place where we launch the cmake command.
This is the top CMakeLists.txt
of the project.
We define the minimum version of cmake
that we support for this project through the directive CMAKE_MINIMUM_REQUIRED.
We identify the project as well as the programming language with the PROJECT directive.
We specify the directories where are located the include files (include and lib) with the INCLUDE_DIRECTORIES
directive.
We define the flags that will be passed as arguments to the compiler
through the ADD_DEFINITIONS
directive. It is optional to do it but the default flags passed to the
compiler are not sufficiently severe to check and report the warnings
and bugs.
We specify the list of sub-directories where are located the sources to
build (lib,
client, man and include) with the ADD_SUBDIRECTORY
directive. We don't specify a directory (second argument of
ADD_SUBDIRECTORY) where to put
all the binaries because we faced some
problems for the installation of the shared library (Bug in cmake ?).
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(roof C) INCLUDE_DIRECTORIES(include lib) ADD_DEFINITIONS(-g -O2 -fsigned-char -freg-struct-return -Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Winline -Werror) ADD_SUBDIRECTORY(lib) ADD_SUBDIRECTORY(client) ADD_SUBDIRECTORY(man) ADD_SUBDIRECTORY(include) |
The directory lib contains all the files to make the library libroof.so.
We define the shared library to build through the directive ADD_LIBRARY. This
directive is passed the name of the library (roof) to build libroof.so, the SHARED keyword to specify
that it is a shared library and the list of source files which are part
of the library: roof.c.
We define the build version (VERSION)
and
the
API
version
(SOVERSION)
of the library through the SET_TARGET_PROPERTIES
directive.
The installation of the library is specified with the INSTALL directive.
It is said that the destination directory from the installation tree
will be lib.
The installation tree is specified by the variable CMAKE_INSTALL_PREFIX.
By default, it is /usr/local.
# Make shared library libroof.so from 'roof.c' ADD_LIBRARY(roof SHARED roof.c) # Set the build version (VERSION) and the API version (SOVERSION) |
The directory client contains the files to make the executable roof.
We first define the target executable roof
with ADD_EXECUTABLE
directive.
We define the dependency of the executable with the libroof.so through
the TARGET_LINK_LIBRARIES
directive. There is
a problem here as we would like to generate an executable called
roof and a library called libroof.so.
Normally, the directive should be written as:
ADD_EXECUTABLE(roof) TARGET_LINK_LIBRARIES(roof roof) |
But cmake complains saying:
CMake Error: Attempt to add link target roof of type: EXECUTABLE to target roof. You can only link to STATIC or SHARED libraries. |
In fact, cmake gets confused because it has the impression that we want to build roof with itself. Hence the use of an intermediate name main in the directives TARGET_LINK_LIBRARIES and ADD_EXECUTABLE. Then, we tell cmake to rename the generated main executable into roof thanks to the directive SET_TARGET_PROPERTIES.
The installation of the program is specified with the INSTALL directive. It is said that the destination directory from the installation tree will be bin. The installation tree is specified by the variable CMAKE_INSTALL_PREFIX. By default, it is /usr/local.
# 'main' depends on some C source files ADD_EXECUTABLE(main main.c) # 'main' depends on libroof.so TARGET_LINK_LIBRARIES(main roof) # In the preceding rules, we can't use 'roof' as target name otherwise # cmake will return in error with TARGET_LINK_LIBRARIES(roof roof): # # CMake Error: Attempt to add link target roof of type: EXECUTABLE # to target roof. You can only link to STATIC or SHARED libraries. # # Hence the SET_TARGET_PROPERTIES to rename main to roof # SET_TARGET_PROPERTIES(main PROPERTIES OUTPUT_NAME roof) # Installation of the program INSTALL(TARGETS main RUNTIME DESTINATION bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) |
The installation of the include files is specified with the INSTALL directive. It is said that the destination directory from the installation tree will be include. The installation tree is specified by the variable CMAKE_INSTALL_PREFIX. By default, it is /usr/local.
INSTALL(FILES roof.h DESTINATION include PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) |
As the project needs to install the manuals in compressed format, we use the directive FIND_PROGRAM to check the presence of the gzip tool (specified after NAMES keyword). The directive is passed the list of directories to find into (/bin, /usr/bin and /usr/local/bin). The result of the command goes into the variable GZIP_TOOL passed as first parameter of the directive. If gzip is found, its path is stored into the variable GZIP_TOOL. If it is not found, GZIP_TOOL is assigned with GZIP_TOOL-NOTFOUND.
The result of the search is checked with the IF directive which returns TRUE if the variable's value is not empty, 0, N, NO, OFF, FALSE, NOTFOUND or <variable>-NOTFOUND. If the test is FALSE, a message is displayed thanks to the MESSAGE directive with a weight set to FATAL_ERROR to stop any future processing.
FIND_PROGRAM(GZIP_TOOL NAMES gzip PATHS /bin /usr/bin /usr/local/bin ) IF(NOT GZIP_TOOL) MESSAGE(FATAL_ERROR "Unable to find 'gzip' program") ENDIF(NOT GZIP_TOOL) |
We first include the script FindGZIP.cmake
to check the presence of gzip
tool.
We use SET
directive to set three variables with the list of source manuals.
Thanks to the string manipulation directive STRING on the preceding
variables, we define three other variables containing the list of
compressed manuals (suffix .gz).
For each source manual, we use ADD_CUSTOM_COMMAND
to generate the specific command which will compress the source manuals.
We define the target man to
be added to the default build target so
that it will be run every time through the directive ADD_CUSTOM_TARGET.
But we make it depend on the source manuals to avoid rebuilding the
manuals each time we invoke make.
The installation of the compressed manuals is specified with
the INSTALL
directives. It is said that the destination directory from the
installation tree will be share/man/manX.
The
installation
tree
is
specified
by
the
variable
CMAKE_INSTALL_PREFIX.
By
default,
it
is
/usr/local.
# Search for gzip program INCLUDE (FindGZIP.cmake) # Lists of source manuals SET(roof_man_src_1 roof.1) SET(roof_man_src_3 roof_cwd.3 roof_login.3 roof_pwd.3 roof_syst.3 roof_delete.3 roof_mkdir.3 roof_retr.3 roof_type.3 roof.3 roof_get_debug_level.3 roof_mv.3 roof_rm.3 roof_get_reply.3 roof_new.3 roof_rmdir.3 roof_cdup.3 roof_initialize.3 roof_nlst.3 roof_set_debug_level.3 roof_close_ctrl.3 roof_list.3 roof_open_ctrl.3 roof_stor.3) SET(roof_man_src_7 roof.7) # Lists of compressed manuals STRING(REGEX REPLACE ".1" ".1.gz" roof_man_gz_1 "${roof_man_src_1}") STRING(REGEX REPLACE ".3" ".3.gz" roof_man_gz_3 "${roof_man_src_3}") STRING(REGEX REPLACE ".7" ".7.gz" roof_man_gz_7 "${roof_man_src_7}") # Compression of the manuals FOREACH(man ${roof_man_src_1} ${roof_man_src_3} ${roof_man_src_7}) ADD_CUSTOM_COMMAND(OUTPUT ${man}.gz COMMAND ${GZIP_TOOL} -c ${man} > ${man}.gz DEPENDS ${man} COMMENT "Building ${man}.gz") ENDFOREACH(man) # Add the manual generation in the global rules ADD_CUSTOM_TARGET(man ALL DEPENDS ${roof_man_gz_1} ${roof_man_gz_3} ${roof_man_gz_7}) # Installation of the manuals INSTALL(FILES ${roof_man_gz_1} DESTINATION "share/man/man1" PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) INSTALL(FILES ${roof_man_gz_3} DESTINATION "share/man/man3" PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) INSTALL(FILES ${roof_man_gz_7} DESTINATION "share/man/man7" PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) |
On this resource,
it
is
explained
how
to
package
a
project.
Loosely
speaking,
cmake
is
associated to the CPack
tool to manage the packages. The following formats are available:
To get an application of CPACK in a real project (with RPM and DEB packaging), refer to the PDIP software maintained by the author of this article.
In this project, we generate a package for project 5.
We just need to add the directive INCLUDE(CPack)
in the top CMakeLists.txt
file. Optionally, it is possible to set some configuration variables
for CPack
like CPACK_PACKAGE_VERSION_MAJOR,
CPACK_PACKAGE_VERSION_MINOR,
CPACK_PACKAGE_VERSION_PATCH...
This generates a new target called package
in the build system.
When this target is built, CPack
is invoked to generate all of the
packages. Internally, CPack
uses the CMake's install directives to
make the package.
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(roof C) INCLUDE_DIRECTORIES(include lib) ADD_DEFINITIONS(-g -O2 -fsigned-char -freg-struct-return -Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Winline -Werror) ADD_SUBDIRECTORY(lib) ADD_SUBDIRECTORY(client) ADD_SUBDIRECTORY(man) ADD_SUBDIRECTORY(include) SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Remote Operations On Files") SET(CPACK_PACKAGE_VENDOR "Rachid Koucha") #SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/ReadMe.txt") SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") SET(CPACK_PACKAGE_VERSION_MAJOR "1") SET(CPACK_PACKAGE_VERSION_MINOR "0") SET(CPACK_PACKAGE_VERSION_PATCH "0") SET(CPACK_PACKAGE_INSTALL_DIRECTORY "CMake ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") #SET(CPACK_STRIP_FILES "bin/MyExecutable") #SET(CPACK_SOURCE_STRIP_FILES "") SET(CPACK_PACKAGE_EXECUTABLES "roof" "FTP client") INCLUDE(CPack) |
Then, invoke the following to trigger the package generation:
$ make package [ 3%] Built target roof [ 7%] Built target main [100%] Built target man Linking C executable CMakeFiles/CMakeRelink.dir/roof Run CPack packaging tool... CPack: Create package using STGZ CPack: Install projects CPack: - Run preinstall target for: roof CPack: - Install project: roof CPack: Compress package CPack: Finalize package CPack: Package .../roof/roof-1.0.0-Linux.sh generated. CPack: Create package using TGZ CPack: Install projects CPack: - Run preinstall target for: roof CPack: - Install project: roof CPack: Compress package CPack: Finalize package CPack: Package .../roof/roof-1.0.0-Linux.tar.gz generated. CPack: Create package using TZ CPack: Install projects CPack: - Run preinstall target for: roof CPack: - Install project: roof CPack: Compress package CPack: Finalize package CPack: Package .../roof/roof-1.0.0-Linux.tar.Z generated. |
As we can see, this generates the STGZ, the TGZ and the TZ packages. The packages do not contain the sources but only the binaries.
Installation from the STGZ into /tmp directory:
$ ./roof-1.0.0-Linux.sh --help Usage: ./roof-1.0.0-Linux.sh [options] Options: [defaults in brackets after descriptions] --help print this message --prefix=dir directory in which to install --include-subdir include the roof-1.0.0-Linux subdirectory --exclude-subdir exclude the roof-1.0.0-Linux subdirectory $ ./roof-1.0.0-Linux.sh --prefix=/tmp --exclude-subdir roof Installer Version: 1.0.0, Copyright (c) Rachid Koucha This is a self-extracting archive. The archive will be extracted to: /tmp Using target directory: /tmp Extracting, please wait... Unpacking finished successfully $ |
The project called PROJECT7 is composed with the following sub-tree (the files can be downloaded from it):
project7 /\ / \ / \ main.c simple |
The project generates one target: an executable called simple.
All the objects are stored into the top level directory. The file main.c needs some configuration
macros that are located in a header file called config.h. The latter will be built
automatically by cmake as it
is setup thanks to some cmake
variables.
The following sub-tree shows the files that have been added to build
the project.
project7 / / | \ / / | \ / / | \ / / | \ main.c config.h.cmake simple CMakeLists.txt |
Once the cmake files are setup, launch cmake to generate the build environment:
$ cd project7 $ cmake . -- The C compiler identification is GNU -- Check for working C compiler: /usr/bin/gcc -- Check for working C compiler: /usr/bin/gcc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Configuring done -- Generating done -- Build files have been written to: .../project7 |
Then, the makefiles are ready to trigger a build with:
$ make Scanning dependencies of target simple [100%] Building C object CMakeFiles/simple.dir/main.c.o Linking C executable simple [100%] Built target simple |
After then, it is possible to clean-up anything generated by the cmake environment with:
$ make clean |
The directory project7
is the top directory of the project. This is the place where we launch
the cmake
command.
This is the top CMakeLists.txt
of the project.
We define the minimum version of cmake
that we support for this project through the directive CMAKE_MINIMUM_REQUIRED.
We identify the project as well as the programming language with the PROJECT directive.
Thanks to the SET directive,
we define a set of variables (PROJECT_NAME,
SIMPLE_VERSION) that will be used to generate the file config.h.
We make the header file config.h via the directive CONFIGURE_FILE. It is passed a file
skeleton (config.h.cmake) which will be
converted into config.h with some
substitutions.
We define the flags that will be passed as arguments to the compiler
through the ADD_DEFINITIONS
directive. It is optional to do it but the default flags passed to the
compiler are not sufficiently severe to check and report the warnings
and bugs.
We specify the target executable simple
with
the ADD_EXECUTABLE
directive.
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(project7 C) SET(PROJECT_NAME SIMPLE) SET(SIMPLE_MAJOR 1) SET(SIMPLE_MINOR 8) SET(SIMPLE_PATCH 6) SET(SIMPLE_VERSION ${SIMPLE_MAJOR}.${SIMPLE_MINOR}.${SIMPLE_PATCH}) CONFIGURE_FILE(config.h.cmake config.h) ADD_DEFINITIONS(-g -O2 -fsigned-char -freg-struct-return -Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Winline -Werror) ADD_EXECUTABLE(simple main.c) |
This file is the skeleton of config.h: all the strings embraced by the character @ (e.g. @PROJECT_NAME@) are placeholders. They are substituted by the cmake variables with the same name (e.g. ${PROJECT_NAME}).
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // File : config.h // Description : Configuration of @PROJECT_NAME@ // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #ifndef CONFIG_H #define CONFIG_H //--------------------------------------------------------------------------- // Name : SIMPLE_VERSION // Usage: Version of @PROJECT_NAME@ //---------------------------------------------------------------------------- #define SIMPLE_VERSION "@SIMPLE_VERSION@" #endif // CONFIG_H |
The file config.h is the result of the substitutions done by the directive CONFIGURE_FILE into the file config.h.cmake.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // File : config.h // Description : Configuration of SIMPLE // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #ifndef CONFIG_H #define CONFIG_H //--------------------------------------------------------------------------- // Name : SIMPLE_VERSION // Usage: Version of SIMPLE //---------------------------------------------------------------------------- #define SIMPLE_VERSION "1.8.6" #endif // CONFIG_H |
The project called PROJECT8
is composed with the following sub-tree (the files can be downloaded from it):
project8
/ / \ \ \
/ / \ \ \
/ / \ \ \
/ / \ \ \
udp_console_u.c udpc_console_k.c udpc Kbuild udpc.ko
|
The
project generates two targets: a user space executable called udpc and a kernel module called udpc.ko.
All the objects are stored into the top level directory. The file udpc_console_u.c needs some
configuration
macros that are located in a header file called config.h. The latter is built
automatically by cmake as it
is setup thanks to some cmake
variables.
The following sub-tree shows the files that have been added to build
the project.
project8
/ / | \ \ \ \
/ / | \ \ \ \
/ / | \ \ \ \
/ / | \ \ \ \
udp_console_u.c udpc_console_k.c config.h.cmake udpc Kbuild udpc.ko CMakeLists.txt
|
Once the cmake files are setup, launch cmake to generate the build environment:
$ cd project8 $ cmake . -- Building UDPC version 1.0.0 -- Configuring done -- Generating done -- Build files have been written to: .../project8 |
Then, the makefiles are ready to trigger a build with:
$ make Scanning dependencies of target kudpc [ 0%] Building udpc.ko [ 50%] Built target kudpc Scanning dependencies of target udpc [100%] Building C object CMakeFiles/udpc.dir/udp_console_u.o Linking C executable udpc [100%] Built target udpc |
After then, it is possible to clean-up anything generated by the cmake environment with:
$ make clean |
The directory project8
is the top directory of the project. This is the place where we launch
the cmake
command.
This is the top CMakeLists.txt
of the project.
We define the minimum version of cmake
that we support for this project through the directive CMAKE_MINIMUM_REQUIRED.
We identify the project as well as the programming language with the PROJECT directive.
Thanks to the SET directive,
we define a set of variables (PROJECT_NAME,
UDPC_VERSION) that will be used to generate the file config.h.
We make the header file config.h via the directive CONFIGURE_FILE. It is passed a file
skeleton (config.h.cmake) which will be
converted into config.h with some
substitutions.
We define the flags that will be passed as arguments to the compiler
through the ADD_DEFINITIONS
directive. It is optional to do it but the default flags passed to the
compiler are not sufficiently severe to check and report the warnings
and bugs.
We specify the target executable udpc
with
the ADD_EXECUTABLE
directive.
To build the Linux kernel module:
cmake_minimum_required(VERSION 2.4) PROJECT(udpc C) SET(PROJECT_NAME UDPC) # Version number SET(UDPC_MAJOR 1) SET(UDPC_MINOR 0) SET(UDPC_PATCH 0) SET(UDPC_VERSION ${UDPC_MAJOR}.${UDPC_MINOR}.${UDPC_PATCH}) MESSAGE(STATUS "Building UDPC version ${UDPC_VERSION}") CONFIGURE_FILE(config.h.cmake config.h) SET(udpc_src udp_console_u.c) SET(udpc_exe udpc) ADD_DEFINITIONS(-g -O2 -fsigned-char -freg-struct-return -Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Winline -Werror) # Build of the program ADD_EXECUTABLE(${udpc_exe} ${udpc_src}) # Build the module EXECUTE_PROCESS(COMMAND uname -r OUTPUT_VARIABLE os_release OUTPUT_STRIP_TRAILING_WHITESPACE) SET(module_path /lib/modules/${os_release}) SET(module_build_path ${module_path}/build) ADD_CUSTOM_COMMAND(OUTPUT udpc.ko COMMAND make -C ${module_build_path} M=`pwd` DEPENDS udp_console_k.c Kbuild COMMENT "Building udpc.ko" ) ADD_CUSTOM_TARGET(kudpc ALL DEPENDS udpc.ko) # Installation of the module SET(module_install_path ${module_path}/kernel) INSTALL(FILES udpc.ko DESTINATION ${module_install_path} PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) # Installation of the program INSTALL(TARGETS udpc DESTINATION "bin" PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) |
This file is the skeleton of config.h: all the strings embraced by the character @ (e.g. @PROJECT_NAME@) are substituted by the cmake variables with the same name (e.g. ${PROJECT_NAME}).
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // File : config.h // Description : Configuration of @PROJECT_NAME@ // License : // // Copyright (C) 2011 Rachid Koucha <rachid dot koucha at free dot fr> // // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // // Evolutions : // // 25-Jan-2011 R. Koucha - Creation // // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #ifndef CONFIG_H #define CONFIG_H //--------------------------------------------------------------------------- // Name : @PROJECT_NAME@_VERSION // Usage: Version of @PROJECT_NAME@ //---------------------------------------------------------------------------- #define @PROJECT_NAME@_VERSION "@UDPC_VERSION@" #endif // CONFIG_H |
The file config.h is the result of the substitutions done by the directive CONFIGURE_FILE into the file config.h.cmake.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // File : config.h // Description : Configuration of UDPC // License : // // Copyright (C) 2011 Rachid Koucha <rachid dot koucha at free dot fr> // // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // // Evolutions : // // 25-Jan-2011 R. Koucha - Creation // // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #ifndef CONFIG_H #define CONFIG_H //--------------------------------------------------------------------------- // Name : UDPC_VERSION // Usage: Version of UDPC //---------------------------------------------------------------------------- #define UDPC_VERSION "1.0.0" #endif // CONFIG_H |
The file Kbuild as explained in Linux documentation embedded in the sources of the kernel (.../Documentation/kbuild/modules.txt and .../Documentation/kbuild/kbuild.txt) to build a kernel module:
# Driver for the UDP based Linux console obj-m += udpc.o udpc-objs := udp_console_k.o |
The project called PROJECT9 is composed with the following sub-tree (the files can be downloaded from it):
project9 / | \ / | \ / | \ / | \ hello.cc CMakeLists.txt hello |
The
project generates one target: an executable called hello.
All
the
objects are stored into the top level directory.
Once
the cmake files are setup,
launch cmake
to generate the build
environment:
Then, the makefiles are ready to trigger a build with:
$ make Scanning dependencies of target hello [100%] Building CXX object CMakeFiles/hello.dir/hello.o Linking CXX executable hello [100%] Built target hello |
The executable is a simple "Hello world" program that uses Qt graphical API. The call to the executable triggers the following:
$ ./hello & |
After then, it is possible to clean-up anything generated by the cmake environment with:
$ make clean |
The directory project9
is the top directory of the project. This is the place where we launch
the cmake
command.
This is the top CMakeLists.txt
of the project.
We define the minimum version of cmake
that we support for this project through the directive CMAKE_MINIMUM_REQUIRED.
We identify the project as well as the programming language with the PROJECT directive. CXX stands for C++ language.
As the program needs Qt include files, we look for the location of
those files thanks to the FIND_PATH
directive. The trick consists to look for a well known sub-directory
name (i.e. QtGui) belonging to the Qt environment. FIND_PATH stores the result of the
search into the QT_INC_DIR variable. The content of this variable is
checked and we extract the root directory of the include files thanks
to the STRING directive.
We define the flags that will be passed as arguments to the compiler
through the ADD_DEFINITIONS
directive. It is optional to do it but the default flags passed to the
compiler are not sufficiently severe to check and report the warnings
and bugs.
We specify the include directory thanks to the INCLUDE_DIRECTORIES directive.
We specify the target executable hello
with
the ADD_EXECUTABLE
directive and the libraries to link with it thanks the TARGET_LINK_LIBRARIES directive.
CMAKE_MINIMUM_REQUIRED(VERSION 2.8) PROJECT(hello CXX) FIND_PATH(QT_INC_DIR NAMES QtGui PATHS /usr/include /usr/include/qt4) IF(NOT QT_INC_DIR) MESSAGE(FATAL_ERROR "Unable to find Qt include files") |
Here are links on open source software using cmake: