After seeing a CMake build issue was fixed using `pkg-config`, I became curious about the utility and examined the usage in and out of CMake.
Introduction
Recently, CMake 3.30.0 was released, and it fixed an issue in the build with SQLite3 libraries. How it was fixed appeared interesting to me. They only added a small script that uses `pkg-config`. I became curious about the utility's potential. I will examine its usage.
Background
When I ran `find_package( SQLite3 REQUIRED )` in my CMake script three weeks ago, it failed and output an error. `find_package` is always a great help to solve dependencies and write portable build scripts with a small effort, thanks to the contributors who abstracted and automated the configurations and the version controls. While being familiar with such circumstances, I've been a bit too lazy and feeling annoyed by the need to write manual configuration when the utility fails.
While looking for solutions to this find_package problem with SQLite3, I found many people on the Internet suggesting different ways, but most of those didn't work for me. Then, I became interested in the source of this confusion.
When I reached the script `FindSQLite3.cmake` under the GitHub repository `Kitware/CMake`, I noticed that it looked different from the one I could see in my environment, which I had with CMake 3.29.6. Fortunately or unfortunately, it had already been fixed since 2024 March but was still waiting for the next release. Now, 3.30.0 was released last week with this fix. Let's upgrade CMake and enjoy the ease of building C++ code with SQLite3.
pkg-config in CMake script
The fix in the script looks quite simple: using the `pkg_check_modules` command from the `PkgConfig` package. It calls the `pkg-config` tool to get the information compilers require and make it available in variables in CMake scripts. Check what variables you can get with it on the CMake documentation here.
Even if you cannot upgrade CMake right now but have or can install pkg-config, including the small script below in your CMake build script, you can solve the issue with SQLite3 by using `pkg-config`. This solution was what I used for the time being.
find_package(PkgConfig)
pkg_check_modules(PC_SQLite3 sqlite3)
set( SQLite3_ROOT "${PC_SQLite3_PREFIX}" )
The variable with the `_PREFIX` suffix is one of the variables that `pkg_check_modules` provides, and the script above sets it to `SQLite3_ROOT`. By default, the `find_path` and `find_library` commands search the paths from the variables with the suffix `_ROOT`, so having `SQLite3_ROOT` allows the old `FindSQLite3.cmake` script to find the required files.
pkg-config in command line
As `pkg-config` is a command-line tool, I became interested in how it can change the C++ code compilation on the command line. So, I gave it a go with the code from my last column.
# install pkg-config
apt-get install pkg-config
# install sqlite3 libraries
apt-get install libsqlite3-dev
# compile the code setting up compile options by pkg-config
g++ --std=c++14 -I./include ./main-2.cpp ./src/SmartDbConnFactory.cpp $(pkg-config --libs --cflags sqlite3)
The compile succeeded, and the built executable works!
However, executing `pkg-config --libs --cflags sqlite3`, I only get `-lsqlite3`. I couldn't feel the power of this tool from it.
So, I also tried it with `opencv`. This time, the command returned a long one. It's going to be interesting.
pkg-config --libs --cflags opencv:
-I/usr/include/opencv4 -lopencv_stitching -lopencv_alphamat -lopencv_aruco -lopencv_barcode -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_cvv -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hdf -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_shape -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_highgui -lopencv_datasets -lopencv_text -lopencv_plot -lopencv_ml -lopencv_videostab -lopencv_videoio -lopencv_viz -lopencv_wechat_qrcode -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_xphoto -lopencv_photo -lopencv_imgproc -lopencv_core
Let's have a simple code with OpenCV. This program will convert an image file into a grayscale image.
#include <iostream>
#include <opencv2/opencv.hpp>
int main() {
cv::Mat image = cv::imread("example.jpg");
cv::Mat grayImage;
cv::cvtColor(image, grayImage, cv::COLOR_BGR2GRAY);
cv::imwrite("example_gray.jpg", grayImage);
return 0;
}
Now, compile it using pkg-config utility.
# install OpenCV libraries and dependencies
apt-get install libopencv-dev
# compile the code setting up compile options by pkg-config
g++ --std=c++14 main.cpp $(pkg-config --libs --cflags opencv4)
The compile was successful, and the image file conversion works! I'm excited about this result. It'll make my coding life easier.