Ta vẫn xoay quanh ví dụ kinh điển là tạo chương trình Hello World, nhưng yêu cầu hiển thị câu đó trên ít nhất 3 ngôn ngữ. ja,en,vi. Chương trình sẽ viết bằng ngôn ngữ C.
[Link tham khảo] Ví dụ được thực hiện trong thư mục /home/oedev/Code/CMake
Nội dung chính gồm các phần sau, 1. Chương trình Hello World cho En. 2. Thêm ngôn ngữ Ja, Vi vào chương trình trên. 3. Thêm ngôn ngữ Ja, Vi trong một tình huống khác.
\============================================================
1.Chương trình Hello World cho En
Ta sẽ có file source như sau: mainapp.c
include
// // Greeting message in En // void greeting_en[] { printf["Hello world n"]; } // // Main functions // int main[int argc, char* argv[]] { greeting_en[]; return 0; }
File sử dụng cho CMake là 1 file CMakeLists.txt
#
Điều kiện về version tối thiểu để đọc được file CMakeList.txt này.
# cmake_minimum_required[VERSION 2.8.12] #
Tên project thường sẽ là tên file chạy
# project [helloworld] #
Định nghĩa mối liên quan giữa file chạy và file nguồn
# add_executable[hellworld mainapp.c]
Đặt cả 2 file trên vào cùng 1 thư mục: Nội dung được kiểm tra bằng lệnh
$ cmake .
2như sau
CMake ├── CMakeLists.txt └── mainapp.c
File CMakeList.txt chính là file định nghĩa source sử dụng ngôn ngữ mà CMake hiểu được. Đến đây, ta thực hiện công việc chính của CMake. Đó là sinh ra Makefiles cho project đơn giản này. Ta phải chuyển vào bên trong thư mục CMake trước khi chạy lệnh dưới đây:
$ cmake .
Dấu . phía sau rất quan trọng, hay có thể thay nó bằng
$ cmake .
3 trong trường hợp này. Tham số thứ 2 là thư mục chưa file CMakeFile.txt Nội dung chạy xong nên như thế này:
oedev@OECrossDev:~/Code/CMake$ cmake . The C compiler identification is GNU 4.8.2 The CXX compiler identification is GNU 4.8.2 Check for working C compiler: /usr/bin/cc Check for working C compiler: /usr/bin/cc works Detecting C compiler ABI info Detecting C compiler ABI info - done Check for working CXX compiler: /usr/bin/c++ Check for working CXX compiler: /usr/bin/c++ works Detecting CXX compiler ABI info Detecting CXX compiler ABI info - done Configuring done Generating done -- Build files have been written to: /home/oedev/Code/CMake
Nội dung thư mục sau khi chạy lệnh trên:
oedev@OECrossDev:~/Code/CMake$ tree -L 2 . ├── CMakeCache.txt ├── CMakeFiles │ ├── 2.8.12.2 │ ├── cmake.check_cache │ ├── CMakeDirectoryInformation.cmake │ ├── CMakeOutput.log │ ├── CMakeTmp │ ├── hellworld.dir │ ├── Makefile2 │ ├── Makefile.cmake │ ├── progress.marks │ └── TargetDirectories.txt ├── cmake_install.cmake ├── CMakeLists.txt ├── mainapp.c └── Makefile
Như ta thấy, có rất nhiều file và thư mục được tạo ra khi ta chạy CMake. Nhưng trong giới hạn bài này ta chỉ quan tâm đến Makefile thôi. Ta cũng thấy rằng chương trình chương được build, hay nói cách khác CMake chỉ làm nhiệm vụ của nó đến đây thôi. Tức là nhiệm vụ của một công cụ sinh Makefiles.
Giờ muốn build project ta vừa tạo lúc đầu [chỉ có 1 file .c], ta sẽ chạy Makefiles thôi.
oedev@OECrossDev:~/Code/CMake$ make Scanning dependencies of target hellworld [100%] Building C object CMakeFiles/hellworld.dir/mainapp.c.o Linking C executable hellworld [100%] Built target hellworld
Kết quả thu được như sau
oedev@OECrossDev:~/Code/CMake$ ls CMakeCache.txt CMakeFiles cmake_install.cmake CMakeLists.txt hellworld mainapp.c Makefile
Ta đã thây file helloword được sinh ra, đây chính là file chạy:
oedev@OECrossDev:~/Code/CMake$ ./hellworld Hello world
Giờ ta sẽ thêm lời chào bằng ngôn ngữ Ja, Vi vào chương trình trên.
2.Thêm ngôn ngữ Ja, Vi vào chương trình trên.
Ta sẽ tổ chức lại source như sau:
oedev@OECrossDev:~/Code/CMake$ tree . ├── CMakeLists.txt ├── include │ ├── greetings_en.h │ ├── greetings_ja.h │ └── greetings_vi.h └── src
├── greetings_en.c
├── greetings_ja.c
├── greetings_vi.c
└── mainapp.c
Do cấu trúc thư mục đã thay đổi, vị trí các file nguồn cũng thế.
Ta cần thay đổi file CMakeList.txt để phù hợp với thay đổi này.
Nội dung file này sẽ thành như sau:#
Điều kiện về version tối thiểu để đọc được file CMakeList.txt này.
# cmake_minimum_required[VERSION 2.8.12] #
Tên project thường sẽ là tên file chạy
# project [helloworld] #
Định nghĩa mối liên quan giữa file chạy và file nguồn
# add_executable[hellworld mainapp.c]
0
Ta sẽ chạy cmake để sinh Makefiles và build chương trình với Makefiles xem kết quả thế nào: Với các sử dụng hàm set: Chạy cmake
oedev@OECrossDev:~/Code/CMake$ cmake . The C compiler identification is GNU 4.8.2 The CXX compiler identification is GNU 4.8.2 Check for working C compiler: /usr/bin/cc Check for working C compiler: /usr/bin/cc works Detecting C compiler ABI info Detecting C compiler ABI info - done Check for working CXX compiler: /usr/bin/c++ Check for working CXX compiler: /usr/bin/c++ works Detecting CXX compiler ABI info Detecting CXX compiler ABI info - done Configuring done Generating done -- Build files have been written to: /home/oedev/Code/CMake
Chạy Make
#
Điều kiện về version tối thiểu để đọc được file CMakeList.txt này.
# cmake_minimum_required[VERSION 2.8.12] #
Tên project thường sẽ là tên file chạy
# project [helloworld] #
Định nghĩa mối liên quan giữa file chạy và file nguồn
# add_executable[hellworld mainapp.c]
2
Kiểm tra thư mục
#
Điều kiện về version tối thiểu để đọc được file CMakeList.txt này.
# cmake_minimum_required[VERSION 2.8.12] #
Tên project thường sẽ là tên file chạy
# project [helloworld] #
Định nghĩa mối liên quan giữa file chạy và file nguồn
# add_executable[hellworld mainapp.c]
3
Kết quả chạy chương trình
#
Điều kiện về version tối thiểu để đọc được file CMakeList.txt này.
# cmake_minimum_required[VERSION 2.8.12] #
Tên project thường sẽ là tên file chạy
# project [helloworld] #
Định nghĩa mối liên quan giữa file chạy và file nguồn
# add_executable[hellworld mainapp.c]
4
Khi thay set command bằng command file [GLOB] thì cho kết quả gần như giống hệt nhau.
2.1Tạo thư mục để build riêng
À, có một điểm cần nói ở đây, vừa ta có thấy rất nhiều file [ngoài Makefile] được sinh ra trong quá trình cmake chạy. Nếu để các file đó chung với thư mục các file source, header ta vừa tạo sẽ gây ra rắc rối, khó quản lý. Ta sẽ tống các file đó vào 1 thư mục, gọi là thư mục build. Cấu trúc thư mục sẽ thay đổi như sau:
#
Điều kiện về version tối thiểu để đọc được file CMakeList.txt này.
# cmake_minimum_required[VERSION 2.8.12] #
Tên project thường sẽ là tên file chạy
# project [helloworld] #
Định nghĩa mối liên quan giữa file chạy và file nguồn
# add_executable[hellworld mainapp.c]
5
Giờ ta sẽ thực hiện toàn bộ quá trình cmake và make bên trong thư mục build
#
Điều kiện về version tối thiểu để đọc được file CMakeList.txt này.
# cmake_minimum_required[VERSION 2.8.12] #
Tên project thường sẽ là tên file chạy
# project [helloworld] #
Định nghĩa mối liên quan giữa file chạy và file nguồn
# add_executable[hellworld mainapp.c]
6
Ta sử dụng .. thay vì . như ở các câu lệnh trước, vì ta đã chuyển vào thư mục ./build nên file CMakeList.txt ở thư mục cha của thư mục này. Ta phải nói cho cmake biết điều đó. Tiếp tục chạy lệnh make, ta sẽ có nội dung thư mục CMake sẽ như sau:
#
Điều kiện về version tối thiểu để đọc được file CMakeList.txt này.
# cmake_minimum_required[VERSION 2.8.12] #
Tên project thường sẽ là tên file chạy
# project [helloworld] #
Định nghĩa mối liên quan giữa file chạy và file nguồn
# add_executable[hellworld mainapp.c]
7
Như ta thấy, toàn bộ nội dung của quá trình chạy cmake và make được giữ trong thư mục ./build, phần đinh nghĩa source code bên ngoài không bị ảnh hưởng gì hết. Để chạy chương trình, ta phải vào thư mục ./build Kết quả vẫn là :
#
Điều kiện về version tối thiểu để đọc được file CMakeList.txt này.
# cmake_minimum_required[VERSION 2.8.12] #
Tên project thường sẽ là tên file chạy
# project [helloworld] #
Định nghĩa mối liên quan giữa file chạy và file nguồn
# add_executable[hellworld mainapp.c]
8
3. Thêm ngôn ngữ Spain[es] trong một tình huống khác
Tình huống khác ở đây là gì? Tôi muốn nói đến tình huống như sau: Giả sử ta có một thư viện chứa lời chào cho 3 ngôn ngữ En, Ja, Vi. Ta cần thêm ngôn ngữ Es để có một chương trình với loài chào của 4 ngôn ngữ En, Ja, Vi, Es.
Trước hết, ta nên hiểu thư viện như thế nào? Trong C/C++ để sử dụng lại được mã nguồn hoặc để bảo vệ mã nguồn. Người ta thường build những mã nguồn muốn sử dụng lại hoặc đưa cho người khác thành các thư viện. Về mặt file ta thấy được, thư viện sẽ có 2 loại: thư viện tĩnh[.a] và thư viện động[.so]. Trong các file đó chứa source đã được đưa về dang nào đó của các hàm mà ta đã viết trong file .c của source.
Nếu thư viện chỉ có thế thôi thì chưa đủ, ta cần phải biết thư viện đó cung cấp gì cho bên ngoài có thể sử dụng được. Có thể là biến toàn cục, có thể là hàm. Các hàm và biến này phải đặt đâu đó trong các file header. Không phải luôn luôn do người viết thư viện cung câp nha. Rồi khi build với source mà ta viết, trình biên dịch sẽ biết cách compile hoặc link cho thích hợp. File header thường được cung cấp kèm theo các file .a[.so]. Nếu không có, thì phải có tài liệu mô tả. Có cả tài liệu và file header là điều lý tưởng nhất.
Giả định rằng, ta có thư viện chưa xử lý hiển thị 3 loài chào En, Ja, Vi. Nhưng ta chỉ có file header mô tả prototype của các hàm mà không thấy được source của nó.