Reputation: 1734
Running into a compilation issue on MacOS 12. Seemingly valid C code is failing to compile into a static library. Compiling this code normally works, and this compiles just fine using the GCC compiler.
MacOS 12 x86-64 MBA.
Compiler version:
$ clang --version
Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
When I compile the code as a static library, I get the follow error when I try to create an executable with the static library.
$ clang -c -Wall -std=c11 ./extern_test.c
$ ar rcs libextern.a extern_test.o
warning: /Library/Developer/CommandLineTools/usr/bin/ranlib: archive library: libextern.a the table of contents is empty (no object file members in the library define global symbols)
$ clang -Wall -std=c11 extern_main.c libextern.a
Undefined symbols for architecture x86_64:
"_external_number", referenced from:
_main in extern_main-61037c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Trying to static link a custom library. The following code example fails if the variable external_number
is defined with the following tentative definition:
// File: extern_test.h
extern int external_number;
// File: extern_test.c
int external_number; // The tentative definition.
However, if this variable is defined with an explicit definition expression, this code works as expected.
// File: extern_test.c
int external_number = 0; // Explicit definition.
// File: extern_test.h
#pragma once
extern int external_number;
// File: extern_test.c
#include "extern_test.h"
int external_number /* = 0 */;
// File: extern_main.c
#include <stdio.h>
#include "extern_test.h"
int main() {
printf("external_number = %d\n", external_number);
return 0;
}
Using the nm
command to look at the linkage of variables given by the compiler.
After compiler the initial .o file, I see the following results for the linkage of the extern_test.c
file.
$ clang -c -Wall -std=c11 ./extern_test.c
$ nm -m extern_test.o
0000000000000004 (common) (alignment 2^2) external _external_number
It's my understanding that "common" linkage is incorrect. If I use the version that sets external_number = 0;
, I get the following results from nm:
% gcc -c -Wall -std=c11 ./extern_test.c
% nm -m ./extern_test.o
0000000000000000 (__DATA,__common) external _external_number
The immediate solution to the problem is to explicitly set the variable to 0 with external_number = 0
, but C allows for global variables to be zero initialized by default, so this should not be required.
Is this a clang compiler bug, or is there something else going on here?
Mac specific documentation on checking external linkage attributes using the nm command: https://developer.apple.com/library/archive/documentation/Performance/Conceptual/CodeFootprint/Articles/ReducingExports.html#//apple_ref/doc/uid/20001864-CJBJFIDD
C example of using an extern tentative declaration to define a global variable:
https://en.cppreference.com/w/c/language/storage_duration
https://en.cppreference.com/w/c/language/extern
Upvotes: 2
Views: 35