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.
|
|
The code themes.c
defines these two global variables.
And the themes.c
compiled from themes.c.o
is also in the archive file: themes.c.o
.
And 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.
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?
Archive
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.
|
|
where 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 .o
files.
Linking problem
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 _default_formats
and _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 -c
command, where the-c
option 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.
Appendix
The following is the relevant documentation written in the macOS libtool manpage.
|
|