1

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
ScottyB
  • 2,167
  • 1
  • 30
  • 46

1 Answers1

2

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 file foo.o but before bar.o. If bar.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.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • That was it. Thanks! I spent days on this. (I'll award the points as soon as StackOverflow lets me in 15 hours.) I must say that it's frustrating that "they" would make a breaking change to something that's been around for years. There are many people like me who are not experts, and a C/C++ program is just a very small part of an overall project they maintain. I'm sure there was a very good reason in someone's mind, but I wish they would think about folks that don't live in their world... – ScottyB Jul 24 '23 at 13:02
  • @ScottyB I agree with you: it can be quite frustrating. I haven't seen the exact reason for that specific change, though. – VonC Jul 24 '23 at 16:13
  • @ScottyB That was also mentioned in [Cannot link static library after upgrading gcc to version 10](https://stackoverflow.com/questions/73572535/cannot-link-static-library-after-upgrading-gcc-to-version-10#comment129925413_73572535). – VonC Jul 24 '23 at 19:47