Search…

Build Chương Trình C/C++ bằng GCC - Nâng Cao

15/12/20206 min read
Hướng dẫn build chương trình C/C++ bằng GCC thông qua Terminal với project nhiều file và link thư viện.

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.omain.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?

  1. Cần chỉ định cho gcc đường dẫn chứa các file header của thư viện sử dụng -I
  2. Cần chỉ định cho gcc đường dẫn chứa các file library của thư viện sử dụng -L
  3. 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:

Bài chung series

IO Stream

IO Stream Co., Ltd

30 Trinh Dinh Thao, Hoa Thanh ward, Tan Phu district, Ho Chi Minh city, Vietnam
+84 28 22 00 11 12
developer@iostream.co

383/1 Quang Trung, ward 10, Go Vap district, Ho Chi Minh city
Business license number: 0311563559 issued by the Department of Planning and Investment of Ho Chi Minh City on February 23, 2012

©IO Stream, 2013 - 2024