The #headers flavor is interpreted as a normal library in Xcode but not in Buck
When depending on mylib#headers
flavoured target, Buck only uses header files as expected and the library is not used at link time. On the other hand, Xcode see the mylib#headers
flavoured target as a complete library and try to link against it, which is not what we want.
An easy example is to take the testcase under test/com/facebook/buck/cxx/testdata/explicit_header_only_caching
apple_binary(
name = "binary",
srcs = ["main.c"],
deps = [
":dylib-exporting-lib1",
":lib3",
],
)
cxx_library(
name = "dylib-exporting-lib1",
srcs = ["stub.c"],
linker_flags = ["-all_load"],
preferred_linkage = "shared",
deps = [":lib1"],
)
cxx_library(
name = "lib1",
srcs = ["lib1.c"],
exported_headers = ["lib1.h"],
header_namespace = "lib1",
preferred_linkage = "static",
deps = [":lib2"],
)
cxx_library(
name = "lib2",
srcs = ["lib2.c"],
exported_headers = ["lib2.h"],
header_namespace = "lib2",
preferred_linkage = "static",
)
cxx_library(
name = "lib3",
srcs = ["lib3.c"],
exported_headers = ["lib3.h"],
header_namespace = "lib3",
preferred_linkage = "static",
deps = [":lib1#headers"],
)
You only need to remember that lib1
contain a function called lib1_function
.
Building with buck
buck build //:binary
Looking at the linking stage of the binary
, we can see:
-o
buck-out/gen/binary
-Xlinker
-map
-Xlinker
buck-out/gen/binary-LinkMap.txt
buck-out/gen/dylib-exporting-lib1#default,shared/libdylib-exporting-lib1.dylib
-Xlinker
-filelist
-Xlinker
buck-out/bin/binary#binary/filelist.txt
So it links against the libdylib-exporting-lib1.dylib
and main.c.o
and liblib3.a
( both contained inside filelist.txt
).
The final binary does not have the implementation of lib1_function
and use a reference to the one living inside libdylib-exporting-lib1.dylib
.
This behavior is expected !
Building with Xcode
buck project --ide Xcode //:binary
then building with Xcode
Looking at the linking stage of the binary
, we can see:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang ... -filelist <path>/binary.LinkFileList -ldylib-exporting-lib1 -llib1 -llib3 ...
It links against the dylib-exporting-lib1.dylib
, lib3.a
, main.c.o
(inside binary.LinkFileList
) but also against lib1.a
(it shouldn't).
The final binary does have the implementation of lib1_function
and does not use the one living inside libdylib-exporting-lib1.dylib
.
This behavior is wrong !
We can clearly see in Xcode that the target lib1
is not really compiled and that it compiles lib1#headers
as a library which is not what we want here.