Tools

Biên dịch mã nguồn C/C++ với CMake và make

[NỘI DUNG BÀI VIẾT ĐƯỢC CẬP NHẬT LIÊN TỤC]

GIỚI THIỆU VỀ MAKE VÀ CMAKE

make là một công cụ giúp tự động hóa quá trình biên dịch mã nguồn, nhờ đó mà chúng ta có thể biên dịch các project phức tạp một cách dễ dàng và nhanh chóng hơn. Các cài đặt cho quá trình biên dịch một project được lưu trong file Makefile để make có thể sử dụng. Tuy nhiên, độ phức tạp của Makefile cũng tỉ lệ thuận với độ phức tạp của project, do đó CMake đã ra đời để giải quyết vấn đề này.

CMake giúp tự động sinh ra Makefile make có thể sử dụng để biên dịch project của bạn. Đối với từng project, các cài đặt cho CMake được lưu trong file CMakeLists.txt.


MỘT SỐ CMAKE COMMAND QUAN TRỌNG

+ cmake_minimum_required() – quy định phiên bản CMake tối thiểu cần cho project.
Ví dụ: cmake_minimum_required(VERSION 2.8)

+ project() – đặt tên cho project hiện tại.
Ví dụ: project(Demo)

+ find_package()
Ví dụ: find_package(OpenCV REQUIRED)

+ set() – tạo hoặc thay đổi giá trị của một biến.
Ví dụ: set(INCLUDE_PATH ../library_1 ../library_2)

+ file() – tạo một danh sách các file thỏa mãn pattern cho trước, thường được sử dụng thay cho set() trong một số trường hợp.
Ví dụ: file(GLOB SOURCE “*.cpp”)

+ add_subdirectory() – thêm một sub-directory vào project, sub-directory này chứa một file CMakeLists.txt riêng. Được dùng để thêm thư viện vào project khi mà thư viện đó lại phụ thuộc vào vài thư viện khác hoặc khi cần thêm Unit Testing.

+ target_include_directories() – chỉ ra các thư mực chứa các file header dành cho một đối tượng cụ thể. Đối tượng này phải được tạo ra bởi lệnh add_library() hoặc add_executable().

+ include_directories() – chỉ ra các thư mục chứa các file header.
Ví dụ: include_directories(../include_1 ../include_2)

+ link_directories() – chỉ ra các thư mục chứa static và shared libraries.
Ví dụ: link_directories(../library_1 ../library_2)

+ add_library() – tạo static và shared library từ các source files.
Ví dụ:
add_library(staticLib STATIC sourcefile_1 sourcefile_2)
add_library(sharedLib SHARED sourcefile_1 sourcefile_2)

+ install() – quy định thư mục sẽ chứa các thư viện vừa được tạo.
Ví dụ: install(TARGETS staticLib sharedLib DESTINATION /usr/local/lib)

+ add_definitions() – thêm các macro cho quá trình biên dịch, được dùng cho CMake < 3.12
Ví dụ: add_definitions(-DVERSION=1.2 -DDEBUG)
+ add_compile_definitions() – thêm các macro cho quá trình biên dịch, được dùng cho CMake >= 3.12
Ví dụ: add_compile_definitions(VERSION=1.2 DEBUG)

+ add_compile_options() – thêm các options cho compiler trong quá trình biên dịch.
Ví dụ: add_compile_options(-std=c99 -Os -Wall)

+ add_executable() – tạo executable file từ các source files.
Ví dụ: add_executable(targetFile sourcefile_A sourcefile_B sourcefile_C)

+ target_link_libraries() – thêm libraries vào target file.
Ví dụ: target_link_libraries(targetFile lib_1 lib_2)


VÍ DỤ 1 – build source code

Biên dịch OpenCV project với CMake và make.
Cấu trúc project:

DemoProject
|—- build
|—- libraries
|—-|—- argparse.h
|—-|—- argparse.cpp
|—- displayImage.cpp
|—- CMakeLists.txt

Trong đó, thư mục build được dùng để chứa các build files và binary file,

File: CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
# Project name
set(PROJECT_NAME DemoProject)

# Target filename
set(TARGET_FILE displayImage)

# Path to libraries 
set(INCLUDE_PATH ./libraries)

# Load required source files in libraries
set(LIB_SOURCES ${INCLUDE_PATH}/argparse.cpp)

# Load all source files in project folder
set(SOURCES displayImage.cpp)

find_package(OpenCV REQUIRED)
message(STATUS "OpenCV_INCLUDE_DIRS = ${OpenCV_INCLUDE_DIRS}")
message(STATUS "OpenCV_LIBS = ${OpenCV_LIBS}")

project(${PROJECT_NAME})

include_directories(${OpenCV_INCLUDE_DIRS} ${INCLUDE_PATH})

add_compile_options(-std=c++11 -Wall)

add_executable(${TARGET_FILE} ${SOURCES} ${LIB_SOURCES})
target_link_libraries(${TARGET_FILE} ${OpenCV_LIBS})

File: displayImage.cpp

#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "argparse.h"

using namespace std;

int main(int argc, char** argv)
{
	ArgumentParser ap(argc, argv);
	ap.add_argument("-f", "--file", "None", "Path to input file");
	ap.parse_args();

    cv::Mat image = cv::imread(ap.get("file"));
    cv::imshow("Image", image);
    cv::waitKey(0);

    return 0;
}

Tạo build files với CMake:
$ cd build
$ cmake ..

Nếu mọi thứ OK, chúng ta sẽ có được kết quả như hình 1 và 2:

Hình 1 – CMake result message
Hình 2 – các build files đã được tạo

Build project với Make:
$ make

Hình 3 – file binary displayImage đã được build thành công

VÍ DỤ 2 – tạo thư viện tĩnh và thư viện động

(Còn tiếp)

Reference:
[1] CMake – Công cụ sinh Makefile, Project file cho source code C/C++.
[2] CMake – useful variables.
[3] Debug vs Release in CMake.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s