This article will describe converting Makefile source tree to CMakeLists.txt source tree manually.
Table of Contents
1 Makefile and CMakeLists.txt
CMakeLists.txt is similar with configure and Makefile. Unix can generate Makefile from CMakeLists.txt with cmake command. This Makefile supports include file dependencies and parallel build. Amount of statement in CMakeLists.txt is equal with Makefile.
2 Makefile source tree
Makefile source tree is as below.
$ tree . ├── include │ └── hello.h ├── lib │ ├── hello.cpp │ └── Makefile ├── Makefile └── src ├── main.cpp └── Makefile 3 directories, 6 files
2.1 Makefile at top directory
Makefile at top directory is as below.
- Build process is done in Makefile of lib and src direcotry. Because src directory needs library in lib directory, build process in lib directory is done before src directory.
LIBNAME := libexample.a PROGNAME := example export LIBNAME export PROGNAME all: lib $(MAKE) -C src lib: $(MAKE) -C lib clean: $(MAKE) -C lib clean $(MAKE) -C src clean .PHONY: lib
2.2 Makefile for library
Makefile in lib directory is as below.
- Getting objects from .cpp source code, creating libexample.a from objects with ar command. Objects will be built with implicit rule.
- Writing dependencies for object in .d file, running build process when header file which is included by source code is update.
CXXFLAGS := -I../include -I. SRC := $(wildcard *.cpp) OBJ := $(patsubst %.cpp,%.o,$(SRC)) DEP := $(patsubst %.cpp,%.d,$(SRC)) all: $(LIBNAME) clean: $(RM) $(DEP) $(OBJ) $(LIBNAME) %.d: %.cpp $(CXX) -MM $(CXXFLAGS) $< | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@ ifneq ($(filter clean,$(MAKECMDGOALS)),clean) -include $(DEP) endif $(LIBNAME): $(OBJ) $(AR) rc $@ $(OBJ)
2.3 Makefile for binary which uses library
Makefile in src directory is as below.
- Getting objects from .cpp source code, creating example from objects with c++ command. Objects will be built with implicit rule.
- .d file is as same as Makefile for library.
CXXFLAGS = -I../include -I. SRC := $(wildcard *.cpp) DEP := $(patsubst %.cpp,%.d,$(SRC)) OBJ := $(patsubst %.cpp,%.o,$(SRC)) all: $(PROGNAME) $(PROGNAME): $(OBJ) ../lib/$(LIBNAME) $(CXX) $(CXXFLAGS) $^ -o $@ %.d: %.cpp $(CXX) -MM $(CXXFLAGS) $< | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@ ifneq ($(filter clean,$(MAKECMDGOALS)),clean) -include $(DEP) endif clean: $(RM) $(DEP) $(OBJ) $(PROGNAME)
2.4 Build with Makefile
Run make command.
$ make /Applications/Xcode.app/Contents/Developer/usr/bin/make -C lib c++ -MM -I../include -I. hello.cpp | sed 's/\(hello\)\.o[ :]*/\1.o hello.d : /g' > hello.d c++ -I../include -I. -c -o hello.o hello.cpp ar rc libexample.a hello.o /Applications/Xcode.app/Contents/Developer/usr/bin/make -C src c++ -MM -I../include -I. main.cpp | sed 's/\(main\)\.o[ :]*/\1.o main.d : /g' > main.d c++ -I../include -I. -c -o main.o main.cpp c++ -I../include -I. main.o ../lib/libexample.a -o example
3 CMakeLists.txt source tree
CMakeLists.txt source tree is as below.
$ tree . ├── CMakeLists.txt ├── include │ └── hello.h ├── lib │ ├── CMakeLists.txt │ └── hello.cpp └── src ├── CMakeLists.txt └── main.cpp 3 directories, 6 files
3.1 CMakeLists.txt at top directory
CMakeLists.txt at top directory is as below.
- The cmake command can separate build directory from source tree. Because the cmake command generates some files, force separating build directory from source tree with checking CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR.
- Add lib directory and src directory to CMakeLists.txt source tree with add_subdirectory. Not writing dependency of lib directory and src directory. The dependency will be determined by target_link_libraries of CMakeLists.txt in src directory.
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) message(FATAL_ERROR "DO NOT BUILD in-tree.") endif() cmake_minimum_required (VERSION 2.8.11) project(example) add_subdirectory(lib) add_subdirectory(src)
3.2 CMakeLists.txt for library
CMakeLists.txt in lib directory is as below.
- Set current directory source codes to variable with AUX_SOURCE_DIRECTORY.
- Create libexample from source codes in variable with add_library. Because this library name is liblibexample.a, rename to libexample.a with set_target_properties.
- Publish library with target_include_directories.
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} source) # Use libexample for avoiding conflicts with add_executable(example). # And rename liblibexample.a to libexample.a add_library(libexample ${source}) set_target_properties(libexample PROPERTIES OUTPUT_NAME "example") target_include_directories(libexample PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
3.3 CMakeLists.txt for binary which uses library
CMakeLists.txt in src directory is as below.
- Setting current directory source codes to variable with AUX_SOURCE_DIRECTORY.
- Creating example from source codes in variable with add_executable. This binary name is example.
- Refer libexample with target_link_libraries. This libexample is name which is set by target_include_directories.
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} source) add_executable(example ${source}) target_link_libraries(example LINK_PUBLIC libexample)
3.4 Build with CMakeLists.txt
Running cmake command create Makefile. Running make command build source code again when source code is update. Need to run cmake command when CMakeLists.txt is update.
$ ls cmake-tree CMakeLists.txt include lib src $ mkdir cmake-tree.build $ cd cmake-tree.build $ cmake ../cmake-tree -G 'Unix Makefiles' $ make [ 50%] Building CXX object lib/CMakeFiles/libexample.dir/hello.cpp.o Linking CXX static library libexample.a [ 50%] Built target libexample [100%] Building CXX object src/CMakeFiles/example.dir/main.cpp.o Linking CXX executable example