Trong hầu hết project C/C++ gồm nhiều file và nhiều module, sử dụng thêm các thư viện liên kết, và GCC có thể hỗ trợ build 1 chương trình như vậy.
Nhắc lại về kiến thức cũ
Để build 1 chương trình, sử dụng cú pháp như sau:
gcc -Wall -o <file thực thi> <các file nguồn>
-Wall
: chỉ định gcc xuất ra tất cả các warning trong quá trình build.-o
: chỉ định gcc build source file thành file thực thi (excutable).<file thực thi>
: là tên file output sau quá trình build và link các thư viện.<các file nguồn>
: các file nguồn đầu vào (.c/.cpp) để build.
Hoặc
gcc -c <các source cần build>
Để build source file thành các file object (chưa build và link ra file thực thi).
gcc -Wall -o main main.c
Hoặc
gcc -c main.c gcc -Wall -o main main.o
Và để chạy chương trình sử dụng lệnh.
./main
Các bước để build 1 chương trình C/C++

Quá trình build 1 chương trình trải qua 4 bước như dưới đây:
- Bước 1: Preprocessing - bộ tiền xử lý thay thế giá trị của các directive:
#define
, #include,#if
, ... trong file mã nguồn .h và .cpp. - Bước 2: Compilation - trình biên dịch chuyển mã nguồn thành mã assembly.
- Bước 3: Assemble - chuyển từ mã assembly sang mã nhị phân (mã máy - machine code).
- Bước 4: Linking - tiến hành liên kết các module và các thư viện liên kết thành file thực thi.
Build module C/C++ với GCC
Giả sử trong Project có 1 module math, chức năng tính toán cộng trừ nhân chia.

Trong thư mục math có 2 file là math.h định nghĩa prototype của các hàm và math.c hiện thực các prototype trong math.h.
File math.h
#ifndef __MATH_H__ #define __MATH_H__ int add(int a, int b); int sub(int a, int b); int mul(int a, int b); int div(int a, int b); #endif
File math.c
#include "math.h" int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int mul(int a, int b) { return a * b; } int div(int a, int b) { return a / b; }
File main.c
#include <stdio.h> #include "math/math.h" int main(int argc, char* argv[]) { printf("Add: %d\n", add(5, 6)); printf("Sub: %d\n", sub(10, 6)); printf("Mul: %d\n", mul(5, 40)); printf("Div: %d\n", div(60, 6)); return 0; }
Trong file main.c sử dụng module math, vì vậy trước chi build main.c phải build math.c sau đó link math.o (được build từ math.c).
- Bước 1: build module math
gcc -c math/math.c
- Sau khi build sẽ được file math.o
- Bước 2: link math.o và main.c
gcc -Wall -o main math.o main.c
- Sau khi chạy xong sẽ tạo được file thực thi main.
Thực thi file main bằng lệnh:
./main
Kết quả:
Add: 11 Sub: 4 Mul: 200 Div: 10
Đây là cách build module C/C++ sử dụng GCC, từ cách làm này có thể build và link các thư viện ngoài ví dụ như FFmpeg, OpenCV, FreeType, SDL, ...
Link thư viện với GCC
Sơ lược thư viện liên kết tĩnh - Static Library
Trong Linux thư viện liên kết tĩnh có phần mở rộng là .a, khi link thư viện liên kết tĩnh với mã để tạo ra file thực thi thì GCC sẽ nạp tất cả mã của thư viện liên kết tĩnh vào file thực thi, vì vậy kích thước của file thực thi lúc này sẽ tăng lên.
Sơ lược thư viện liên kết động - Dynamic Library
Trong Linux thư viện liên kết động có phần mở rộng là .so, khác với thư viện liên kết tĩnh, khi link thư viện liên kết động mã thực thi sẽ không link vào file thực thi. Khi thực thi chương trình mới tìm các thư viện liên kết động và nạp vào bộ nhớ. Vì vậy mà file thực thi sau khi link xong sẽ không gia tăng kích thước từ thư viện.
Cả 2 thư viện này đều chứa mã nhị phân và có những file header .h chứa các prototype của các hàm trong thư viện.
Đa số các thư viện lớn như FFmpeg, OpenCV, SDL sau khi build xong sẽ tạo thư viện liên kết động và cả thư viện liên kết tĩnh.
Dưới đây là 1 đoạn mã sử dụng OpenCV
#include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> using namespace std; using namespace cv; int main(int argc, char* argr[]) { cout << Mat::zeros(4, 4, CV_8UC1); return 0; }
Vậy làm sao build được chương trình này?
- Cần chỉ định cho gcc đường dẫn chứa các file header của thư viện sử dụng -I
- Cần chỉ định cho gcc đường dẫn chứa các file library của thư viện sử dụng -L
- Cần link các module thư viện liên kết.
Ví dụ thư viện OpenCV sẽ có:
/usr/local/include
: đường dẫn chứa header của thư viện./usr/local/lib
: đường dẫn chứa lib của thư viện.
Và các module của OpenCV:
ImageMagick libcairo-gobject.a libopencv_calib3d.dylib libpcre32.dylib cairo libcairo-gobject.dylib libopencv_core.3.1.0.dylib libpcrecpp.o.dylib cmake libcairo-script-interpreter.2.dylib libopencv_core.3.1.dylib libpcrecpp.a dtrace libcairo-script-interpreter.a libopencv_core.dylib libpcrecpp.dylib gio libcairo-script-interpreter.dylib libopencv_features2d.3.1.0.dylib libpcreposix.o.dylib girepository-1.0 libcairo.2.dylib libopencv_features2d.3.1.dylib libpcreposix.a glib-2.0 libcairo.a libopencv_features2d.dylib libpcreposix.dylib gobject-introspection libcairo.dylib libopencv_flann.3.1.0.dylib libpixman-1.0.dylib itc14.0.0 libfontconfig.1.dylib libopencv_flann.3.1.dylib libpixman-1.a libMagick++-6.916.6.dylib libfontconfig.a libopencv_flann.dylib libpixman-1.dylib libMagick++-6.Q16.a libfontconfig.dylib libopencv_highgui.3.1.0.dylib libpng.a libMagick++-6.916.dylib libfreetype.6.dylib libopencv_highgui.3.1.dylib libpng.dylib libMagick++-6.916.la libfreetype.a libopencv_highgui.dylib libpng16.16.dylib libMagickCore-6.916.2.dylib libfreetype.dylib libopencv_imgcodecs.3.1.0.dylib libpng16.a libMagickCore-6.916.a libfreetype.la libopencv_imgcodecs.3.1.dylib libpng16.dylib libMagickCore-6.Q16.dylib libfribidi.0.dylib libopencv_imgcodecs.dylib libpostproc.54.0.100.dylib libMagickCore-6.916.la libfribidi.dylib libopencv_imgproc.3.1.0.dylib libpostproc.54.dylib libMagickWand-6.916.2.dylib libgio-2.0.0.dylib libopencv_imgproc.3.1.dylib libpostproc.a libMagickWand-6.Q16.a libgio-2.0.a libopencv_imgproc.dylib libpostproc.dylib libMagickWand-6.916.dylib libgio-2.0.dylib libopencv_m1.3.1.0.dylib libswresample.2.1.100.dylib libMagickWand-6.Q16.la libgirepository-1.0.1.dylib libopencv_m1.3.1.dylib libswresample.2.dylib libSDL2-2.0.0.dylib libgirepository-1.0.a libopencv_ml.dylib libswresample.a libSDL2.a libgirepository-1.0.dylib libopencv_objdetect.3.1.0.dylib libswresample.dylib libSDL2.dylib libglib-2.0.0.dylib libopencv_objdetect.3.1.dylib libswscale.4.1.100.dylib libSDL2.la libglib-2.0.a libopencv_objdetect.dylib libswscale.4.dylib libSDL2_test.a libglib-2.0.dylib libopencv_photo.3.1.0.dylib libswscale.a libSDL2main.a libgmodule-2.0.0.dylib libopencv_photo.3.1.dylib libswscale.dylib libass.5.dylib libgmodule-2.0.a libopencv_photo.dylib libtc18.6.dylib libass.a libgmodule-2.0.dylib libopencv_shape.3.1.0.dylib libtclstub8.6.a libass.dylib libgobject-2.0.0.dylib libopencv_shape.3.1.dylib libtiff.5.dylib libavcodec.57.48.101.dylib libgobject-2.0.a libopencv_shape.dylib libtiff.a libavcodec.57.dylib libgobject-2.0.dylib libopencv_stitching.3.1.0.dylib libtiff.dylib libavcodec.a libgthread-2.0.0.dylib libopencv_stitching.3.1.dylib libtiffxx.5.dylib libavcodec.dylib libgthread-2.0.a libopencv_stitching.dylib libtiffxx.a libavdevice.57.0.101.dylib libgthread-2.0.dylib libopencv_superres.3.1.0.dylib libtiffxx.dylib libavdevice.57.dylib libharfbuzz-gobject.o.dylib libopencv_superres.3.1.dylib libtk8.6.dylib libavdevice.a libharfbuzz-gobject.a libopencv_superres.dylib libtkstub8.6.a libavdevice.dylib libharfbuzz-gobject.dylib libopencv_ts.a libxvidcore.4.dylib libavfilter.6.47.100.dylib libharfbuzz-icu.o.dylib libopencv_video.3.1.0.dylib libxvidcore.a libavfilter.6.dylib libharfbuzz-icu.a libopencv_video.3.1.dylib node_modules libavfilter.a libharfbuzz-icu.dylib libopencv_video.dylib pkgconfig libavfilter.dylib libharfbuzz.o.dylib libopencv_videoio.3.1.0.dylib python2.7 libavformat.57.41.100.dylib libharfbuzz.a libopencv_videoio.3.1.dylib sqlite3.7.15.1 libavformat.57.dylib libharfbuzz.dylib libopencv_videoio.dylib tcl8
Gõ lệnh để build như sau:
g++ -Wall -o main main.cpp -I/usr/local/include -L/usr/local/lib -lopencv_calib3d -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_highgui -lopencv_imgcodecs -lopencv_imgproc -lopencv_ml -lopencv_objdetect -lopencv_photo -lopencv_shape -lopencv_stitching -lopencv_superres -lopencv_ts -lopencv_video -lopencv_videoio -lopencv_videostab
Vì OpenCV được viết bằng C++ nên sử dụng g++ để build thay vì dùng gcc:
Sau khi gõ dòng lệnh ./main
để thực thi chương trình, kết quả như sau:
[ 0, 0, 0, 0; 0, 0, 0, 0; 0, 0, 0, 0; 0, 0, 0, 0 ]
1 nhược điểm rất lớn là cần gõ trên Terminal khá nhiều nếu project có rất nhiều file .c. Để khắc phục nhược điểm này có thể viết makefile.
Nếu sử dụng IDE để thao tác thì việc link các thư viện này hoàn toàn tương tự, có thể xem clip link thư viện OpenCV trong Xcode: