I recently saw an issue: irssi 1.4.1 fails to build on darwin arm64, and it’s phenomenon is that it reports an error when linking.
themes.c defines these two global variables.
themes.c compiled from
themes.c.o is also in the archive file:
themes.c.o also defines these two symbols.
So, what is the problem? It looks like the link provides the
libfe_common_core.a argument, and the
.a also contains
themes.c.o, and the symbols we are looking for are defined, so why is there an
Undefined symbols problem?
The answer lies in the COMMON symbols.
The reasons and principles of the COMMON symbols can be found in detail in MaskRay’s blog All about COMMON symbols, which describes this issue in great detail from the linker’s point of view from the linker’s point of view.
In short, the COMMON symbol was introduced to interoperate with Fortran. It corresponds to a global variable in C without an initialization statement. In fact, at the end, it is still saved in the .bss segment and cleared by default. So.
The two statements end up with similar results, except that the first one is a COMMON Symbol and the second one is a normal GLOBAL Symbol.
This still doesn’t seem to be related to the
Undefined symbols error. What is the problem?
A static library is usually given as an Archive, with the suffix
.a. It is actually a collection of
.o packages, plus an index, i.e. a separate table that holds which symbols are defined for each
.o. The advantage of this is that when looking for symbols, instead of traversing
.o, you can look for the relevant symbols directly in the index.
To create an Archive, the
ar command can be used on Linux to.
c means create and
r means insert (and overwrite).
On macOS, you have to use
libtool -static to create Archive.
Otherwise an error will be reported when linking.
Then you can use the
ar t command to see what is in the Archive.
The index of the Archive can be viewed with the
nm --print-armap command.
So we already know about Archive: it is a collection of multiple
.o files, and it implements an index. When linking, the index is used to find
.o instead of traversing all
So, going back to the linking problem at the beginning, since we have confirmed that the symbol is defined in the
.o file and that this
.o is indeed in the
.a file, there is only one last possibility left: the symbol is not in the index.
Trying with the
nm --print-armap command, I found that the
_current_theme above are only defined in the corresponding
.o, but not in the Archive index section.
Netizen @ailin-nemui pointed out the problem and provided a link: OS X linker unable to find symbols from a C file which only contains variables. The important point it makes is that the macOS version of ar/ranlib/libtool does not create indexes for COMMON symbols by default. So, the solution is clear:
- The first one is not to create COMMON symbols: add the compile option
-fno-common, which is the default in newer compilers.
- The second is to create an index for the COMMON symbol: use the
libtool -static -ccommand, where the
-coption turns on indexing for the COMMON symbol.
- Third, modify the code: set an initialization value for the global variable
This way, the problem is solved properly.
The following is the relevant documentation written in the macOS libtool manpage.