STDIO
Tìm kiếm gần đây
    Nội dung
    0
    0
    Chia sẻ
    Nội dung
    0
    0
    Chia sẻ

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

    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.
    03/11/2020 15/12/2020 6 phút đọc
    Build Chương Trình C/C++ bằng GCC - Nâng Cao

    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

    0 Bình luận
    Modern C++

    Modern C++

    STDIO Training - Đào Tạo Lập Trình C++.

    Khi bạn nhấn vào sản phẩm do chúng tôi đề xuất và mua hàng, chúng tôi sẽ nhận được hoa hồng. Điều này hỗ trợ chúng tôi có thêm kinh phí tạo nhiều nội dung hữu ích. Tìm hiểu thêm.
    STDIO

    Trang chính

    Công ty TNHH STDIO

    • 30, Trịnh Đình Thảo, Hòa Thạnh, Tân Phú, Hồ Chí Minh
      +84 28.36205514 - +84 942.111912
      developer@stdio.vn
    • 383/1 Quang Trung, Phường 10, Quận Gò Vấp, Hồ Chí Minh
      Số giấy phép ĐKKD: 0311563559 do sở Kế hoạch và Đầu Tư TPHCM cấp ngày 23/02/2012
    ©STDIO, 2013 - 2021