Issue
I got a g++ compile error when trying to upgrade from Docker image php:7.2-apache to php:7.4-apache. The base image of php:7.2-apache is debian:buster-slim, and the base image of 7.4-apache is debian:bullseye-slim.
I then recreated the problem between debian:buster-slim and debian:bullseye-slim.
Here's a dockerfile that works:
FROM debian:buster-slim
RUN apt-get -y update && \
apt-get install --yes --no-install-recommends \
openssh-client \
git \
nano \
cron \
ffmpeg \
libjpeg-dev \
libmariadb-dev-compat \
libpng-dev \
libxpm-dev \
libfreetype6-dev \
libwebp-dev \
libjpeg62-turbo-dev \
libgd-dev \
g++
WORKDIR "/test"
RUN printf "#include <stdio.h>\n#include <mysql.h>\n#include <jpeglib.h>\nusing namespace std;\nint main(int argc, const char * argv[]) {\nMYSQL mysql;\nmysql_init(&mysql);\nstruct jpeg_decompress_struct cinfo;\n}" > main.cpp
RUN g++ -std=c++11 -I/usr/include/mysql -lmysqlclient -ljpeg main.cpp -o test
Here's a dockerfile that doesn't work:
FROM debian:bullseye-slim
RUN apt-get -y update && \
apt-get install --yes --no-install-recommends \
openssh-client \
git \
nano \
cron \
ffmpeg \
libjpeg-dev \
libmariadb-dev-compat \
libpng-dev \
libxpm-dev \
libfreetype6-dev \
libwebp-dev \
libjpeg62-turbo-dev \
libgd-dev \
g++
WORKDIR "/test"
RUN printf "#include <stdio.h>\n#include <mysql.h>\n#include <jpeglib.h>\nusing namespace std;\nint main(int argc, const char * argv[]) {\nMYSQL mysql;\nmysql_init(&mysql);\nstruct jpeg_decompress_struct cinfo;\n}" > main.cpp
RUN g++ -std=c++11 -I/usr/include/mysql -lmysqlclient -ljpeg main.cpp -o test
The errors I get include:
main.cpp:(.text+0x23): undefined reference to `mysql_init'
(There's a similar error for the jpeg library if I remove mysql from the dockerfile.)
I believe the problem is that it can't link the mysqlclient and jpeg libraries.
Anyone know the root cause and how to fix? Thanks!
NOTE: I edited the question so that the dockerfiles are self-contained with a "mini" C program (RUN printf...). The image can be built by anyone using:
docker build . -t myimage
Solution
I do reproduce the failed build (W11, Docker Desktop 4.21.1 (114176), Docker 24.0.2):
=> ERROR [5/5] RUN g++ -std=c++11 -I/usr/include/mysql -lmysqlclient -ljpeg main.cpp -o test 0.5s
------
> [5/5] RUN g++ -std=c++11 -I/usr/include/mysql -lmysqlclient -ljpeg main.cpp -o test:
0.446 /usr/bin/ld: /tmp/cclUFOxL.o: in function `main':
0.446 main.cpp:(.text+0x23): undefined reference to `mysql_init'
0.448 collect2: error: ld returned 1 exit status
------
Dockerfile:22
--------------------
20 | WORKDIR "/test"
21 | RUN printf "#include <stdio.h>\n#include <mysql.h>\n#include <jpeglib.h>\nusing namespace std;\nint main(int argc, const char * argv[]) {\nMYSQL mysql;\nmysql_init(&mysql);\nstruct jpeg_decompress_struct cinfo;\n}" > main.cpp
22 | >>> RUN g++ -std=c++11 -I/usr/include/mysql -lmysqlclient -ljpeg main.cpp -o test
--------------------
ERROR: failed to solve: process "/bin/sh -c g++ -std=c++11 -I/usr/include/mysql -lmysqlclient -ljpeg main.cpp -o test" did not complete successfully: exit code: 1
But this Dockerfile worked:
FROM debian:bullseye-slim
RUN apt-get -y update && \
apt-get install --yes --no-install-recommends \
openssh-client \
git \
nano \
cron \
ffmpeg \
libjpeg-dev \
libmariadb-dev-compat \
libpng-dev \
libxpm-dev \
libfreetype6-dev \
libwebp-dev \
libjpeg62-turbo-dev \
libgd-dev \
g++
WORKDIR "/test"
RUN printf "#include <stdio.h>\n#include <mysql.h>\n#include <jpeglib.h>\nusing namespace std;\nint main(int argc, const char * argv[]) {\nMYSQL mysql;\nmysql_init(&mysql);\nstruct jpeg_decompress_struct cinfo;\n}" > main.cpp
RUN g++ -std=c++11 main.cpp -I/usr/include/mysql -lmysqlclient -ljpeg -o test
Meaning not:
RUN g++ -std=c++11 -I/usr/include/mysql -lmysqlclient -ljpeg main.cpp -o test
But instead:
RUN g++ -std=c++11 main.cpp -I/usr/include/mysql -lmysqlclient -ljpeg -o test
The source file main.cpp
is placed before the -l
options.
And note that if you were compiling multiple files, they should all come before the -l
options.
For example: g++ -std=c++11 file1.cpp file2.cpp -I/usr/include/mysql -lmysqlclient -ljpeg -o test
.
The buster-slim image includes a gcc-8-base:amd64=8.3.0-6
.
The bullseye-slim image includes a gcc-10-base:amd64=10.2.1-6
.
The GCC 10 release included several linker changes.
Most
--param
values can now be specified at translation unit granularity. This includes all parameters controlling the inliner and other inter-procedural optimizations.
Unlike earlier releases, GCC 10 will ignore parameters controlling optimizations specified at link-time and apply parameters specified at compile-time in the same manner as done for optimization flags.
And the current gcc linker option documentation includes:
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified.
Thus,foo.o -lz bar.o
searches library ‘z
’ after filefoo.o
but beforebar.o
. Ifbar.o
refers to functions in ‘z
’, those functions may not be loaded.
It is best practice to always list libraries after your source or object files when compiling with gcc
or g++
. That ensures that the linker will correctly resolve all symbols. That is why moving the -l
options to the end of the command solved your problem.
Answered By - VonC Answer Checked By - Candace Johnson (WPSolving Volunteer)