An annoyance with jpeglib.h and RawStudio

In the last few days I’ve caught up with building Darktable‘s git master, and was being driven slightly crazy by an error that showed up in the link stage.

The error is as follows:

Undefined                       first referenced
 symbol                             in file
jpeg_CreateDecompress(jpeg_decompress_struct*, int, unsigned int) libdarktable.so
jpeg_resync_to_restart(jpeg_decompress_struct*, int) libdarktable.so
jpeg_read_scanlines(jpeg_decompress_struct*, unsigned char**, unsigned int) libdarktable.so
jpeg_read_header(jpeg_decompress_struct*, int) libdarktable.so
jpeg_std_error(jpeg_error_mgr*)     libdarktable.so
jpeg_finish_decompress(jpeg_decompress_struct*)     libdarktable.so
jpeg_destroy_decompress(jpeg_decompress_struct*)     libdarktable.so
jpeg_start_decompress(jpeg_decompress_struct*)     libdarktable.so
ld: fatal: symbol referencing errors. No output written to darktable
collect2: ld returned 1 exit status
gmake[2]: *** [src/darktable] Error 1
gmake[1]: *** [src/CMakeFiles/darktable.dir/all] Error 2
gmake: *** [all] Error 2

What made this all the more infuriating is a quick elfdump -d on libdarktable.so showed that libjpeg.so appeared to be linked in correctly.

As a brute-force way of seeing what jpeg_* symbols were being referred to, I ran nm over each object file, dumped that output to a file and then had a look at the output. Lo and behold, one smoking gun!:

src/libdarktable.so
[9494]      |         0|         0|NOTY |GLOB |0    |UNDEF  |_Z14jpeg_std_errorP14jpeg_error_mgr
[9074]      |         0|         0|NOTY |GLOB |0    |UNDEF  |_Z16jpeg_read_headerP22jpeg_decompress_structi
[7599]      |         0|         0|NOTY |GLOB |0    |UNDEF  |_Z19jpeg_read_scanlinesP22jpeg_decompress_structPPhj
[8567]      |         0|         0|NOTY |GLOB |0    |UNDEF  |_Z21jpeg_CreateDecompressP22jpeg_decompress_structij
[7492]      |         0|         0|NOTY |GLOB |0    |UNDEF  |_Z21jpeg_start_decompressP22jpeg_decompress_struct
[7387]      |         0|         0|NOTY |GLOB |0    |UNDEF  |_Z22jpeg_finish_decompressP22jpeg_decompress_struct
[9332]      |         0|         0|NOTY |GLOB |0    |UNDEF  |_Z22jpeg_resync_to_restartP22jpeg_decompress_structi
[9327]      |         0|         0|NOTY |GLOB |0    |UNDEF  |_Z23jpeg_destroy_decompressP22jpeg_decompress_struct
[9053]      |    508832|       254|FUNC |GLOB |0    |13     |dt_imageio_jpeg_read_header
[8554]      |         0|         0|FUNC |GLOB |0    |UNDEF  |jpeg_CreateDecompress
[9115]      |         0|         0|FUNC |GLOB |0    |UNDEF  |jpeg_destroy_decompress
[8027]      |         0|         0|FUNC |GLOB |0    |UNDEF  |jpeg_read_header
[7509]      |         0|         0|FUNC |GLOB |0    |UNDEF  |jpeg_read_scanlines
[8449]      |         0|         0|FUNC |GLOB |0    |UNDEF  |jpeg_resync_to_restart
[8763]      |         0|         0|FUNC |GLOB |0    |UNDEF  |jpeg_start_decompress
[9206]      |         0|         0|FUNC |GLOB |0    |UNDEF  |jpeg_std_error

Notice that there are two entries for each of those functions, one a function with global scope, the other a globally-scoped element with no type (NOTY) specified. The NOTY form is mangled, which indicates the presence of C++ somewhere.

Now wait a second... libjpeg.so is a C library, not C++... so what’s going on?

It turns out that with the recent update of RawSpeed, DngDecoderSlices.cpp now calls jpeglib.h functions directly. This is a problem on Solaris because Solaris’ version of jpeglib.h does not have the appropriate C++ guards around the contents of the header file.

While I’ve filed a bug against jpeglib.h requesting that those guards be added, in the meantime I’ve taken a copy of the system version, dumped it into /opt/darktable/include and ensured that my CFLAGS and CXXFLAGS variables have -I/opt/darktable/include.

The diffs are as follows:

$ diff -U2 /usr/include/jpeglib.h jpeglib.h
--- /usr/include/jpeglib.h      Fri Oct 21 09:35:15 2011
+++ jpeglib.h   Mon Aug 20 23:51:35 2012@@ -14,4 +14,8 @@ #define JPEGLIB_H

+#ifdef __cplusplus
+extern "C" {
+#endif
+ /*  * First we include the configuration files that record how this
@@ -1094,3 +1098,7 @@
#endif

+#ifdef __cplusplus
+}
+#endif
+ #endif /* JPEGLIB_H */