The client library — libmysqlclient — is part of the same source code repository as the server. It comes both as a dynamic link library (.so), also called a shared library, and as a static link library (.a). During the 5.7 development cycle, we’ve made several improvements to the library, which has resulted in a bump from ABI version 18 to version 20. This is the fourth and final part in a series of blog posts focusing on the client library. If you want to read the whole series, go back to the first post, called The API, the whole API and nothing but the API.
In my previous post, I covered a few changes we’ve made to the build process. This time, we’re going to use some of that to build a simple example application using modern tools.
Hello, MySQL World
We’re going to write a simple application in C that connects to a MySQL server and executes queries. The entire source code of this project can be downloaded from http://github.com/nryeng/hello-mysql-world.
Prerequisites
We’re going to use the following tools:
- CMake
- pkg-config
- libmysqlclient version 20 (comes with MySQL 5.7)
- GCC
The installation details are different for every OS, so it would take a whole new series of blog posts to explain how to install all these. I’m simply going to assume that they are installed.
The source code
The application itself is very simple: It asks for host name, port number, user name, password and database name. It then connects to the server and lets you execute queries. The full source code is in the file hello.c in the GitHub repo.
Our simple application will be dynamically linked with the client library.
Using CMake to build our application
CMake is a cross-platform build system. The goal of this blog post is to demonstrate how simple it is to add a libmysqlclient dependency to CMake projects using pkg-config, not to teach CMake basics, but I’ll explain a little about each line anyways.
Our CMake script looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# The minimum required version hasn't been tested. Feel free to adjust # downwards if necessary. cmake_minimum_required(VERSION 3.0) project(hello-mysql-world C) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") include(FindPkgConfig) pkg_check_modules(LIBMYSQLCLIENT REQUIRED mysqlclient) foreach(FLAG ${LIBMYSQLCLIENT_CFLAGS_OTHER}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAG}") endforeach() link_directories(${LIBMYSQLCLIENT_LIBRARY_DIRS}) add_executable(hello hello.c) target_include_directories(hello PRIVATE ${LIBMYSQLCLIENT_INCLUDE_DIRS}) target_link_libraries(hello PRIVATE ${LIBMYSQLCLIENT_LIBRARIES}) |
Line 3 tells you which CMake version is required to run this script. I have 3.0.2, so I put 3.0 there. It might also work with older versions if you lower that number.
Line 4 says that this project is called hello-mysql-world and that it’s written in C. And since I’m using C99, I’ve added the C flag for that in line 5.
The next few lines is where the pkg-config magic happens. In line 7, we include the FindPkgConfig module, a CMake module that uses pkg-config to find libraries. Then, in line 8, we use the pkg_check_modules command provided by that module to find the libmysqlclient library. Let’s go through the parameters one by one.
The result of the pkg_check_modules command is that a number of variables will be set, and the first parameter to the command is the prefix for those variables. I’ve chosen LIBMYSQLCLIENT so that my variables will be called LIBMYSQLCLIENT_FOUND (which is set to 1 if the library is found), LIBMYSQLCLIENT_LIBRARIES (which is the list of libraries to link with), etc. A full list of variables can be found in the FindPkgConfig documentation.
The second parameter, REQUIRED, says that CMake should fail if the library isn’t found. Our application won’t build without the library, so I’ve chosen to fail fast if pkg-config can’t locate the library.
Third and last is the name of the library, or module, as it is called in pkg-config terms. Typically, this is the same as what you specify in the -l option on the linker command line, i.e., the name of the library without the “lib” prefix. In our case, that means “mysqlclient”.
The FindPkgConfig module will call pkg-config to find out everything it can about the library and set CMake variables for everything.
Lines 10–12 loop through the LIBMYSQLCLIENT_CFLAGS_OTHER list and append each flag to CMAKE_C_FLAGS. The list is created by pkg_check_modules and contains all the C flags that are needed to compile, except the flags for include directories and linking, which we will specify in a different way.
Line 14 tells CMake to tell the linker to look for libraries in the directory where pkg_check_modules found the libmysqlclient library.
Lines 16–18 specifies that hello.c will be compiled to make an executable called “hello”, and to build it we need to include header files from LIBMYSQLCLIENT_INCLUDE_DIR and link with the libraries listed in LIBMYSQLCLIENT_LIBRARIES. Both these variables are set by the pkg_check_modules command.
Building and running
Now that we have both the source code and the build script, we can try to build the application:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$ git clone https://github.com/nryeng/hello-mysql-world.git $ cd hello-mysql-world $ mkdir bld; cd bld $ cmake .. -- The C compiler identification is GNU 4.9.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 -- Found PkgConfig: /usr/bin/pkg-config (found version "0.28") -- checking for module 'mysqlclient' -- found mysqlclient, version 20.0.9 -- Configuring done -- Generating done -- Build files have been written to: /home/nryeng/hello-mysql-world/bld $ make Scanning dependencies of target hello [100%] Building C object CMakeFiles/hello.dir/hello.c.o Linking C executable hello [100%] Built target hello |
As we can see in line 18, CMake finds libmysqlclient version 20.0.9 and is able to build the application. Let’s try it out!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ ./hello Hello, MySQL World! Let's start by connecting to the database. Server name: 127.0.0.1 Server port: 13000 User name: root Password: Database: test You're now connected to the server. Query (or 'quit'): CREATE TABLE foo (id INT AUTO_INCREMENT PRIMARY KEY, a VARCHAR(20), b VARCHAR(20)); No result. Query (or 'quit'): INSERT INTO foo(a,b) VALUES ('abc', '123'), ('foo', 'bar'), ('MySQL', 'Rocks!'); No result. Query (or 'quit'): SELECT * FROM foo; [1] [abc] [123] [2] [foo] [bar] [3] [MySQL] [Rocks!] Query (or 'quit'): quit |
That’s it! We wrote a simple MySQL client and used CMake and pkg-config to build it.
In part 2 of this series, we talked about what the version number means and how the linker uses it to find the right library. Let’s look at the library dependencies for our hello application:
1 2 3 4 5 6 7 8 9 10 11 |
$ ldd hello linux-vdso.so.1 => (0x00007ffece61b000) libmysqlclient.so.20 => /usr/local/mysql/lib/libmysqlclient.so.20 (0x00007f25ea729000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f25ea35f000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f25ea15b000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f25e9f53000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f25e9d35000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f25e9a26000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f25e971e000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f25e9508000) /lib64/ld-linux-x86-64.so.2 (0x00007f25ead9c000) |
In line 3 we see that the application depends on libmysqlclient.so.20, which is the 5.7 client library. This means that we’ve linked this applications with version 20 of the client library, and we only know that version 20 will work. In this case I happen to know that version 18, and maybe even older version, works, but the linker can’t take the chance on that. If I want to use another version, I have to recompile.
Summary
This concludes our four-part series of libmysqlclient blog posts. We’ve covered several topics relating to shared libraries in general and the MySQL client library in particular:
And in the end, we summed it all up in this final example. I hope you’ve learned something!
If you have any questions or comments, please use the comment field below.