Create a fully static C++ binary in Bazel - c++

Is it possible to create a fully static binary in Bazel or is there a bug in GCC or bazel preventing me.
This is the error that I get
/bin/ld.gold: error: /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginT.o: requires dynamic R_X86_64_32 reloc against '__TMC_END__' which may overflow at runtime; recompile with -fPIC
Which if I understand correctly is a version libstdc++ that is not statically linked. Was wondering if there was a version of libstdc++ that is statically linked that I could make Bazel use.
Tried looking at this issue on Bazel's repo but the workarounds mentioned do not work for me
https://github.com/bazelbuild/bazel/issues/8672
Info Dump
Bazel version:3.3.1
GCC version: gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
OS: Ubuntu 20.04 in a Docker container
My build file
cc_binary(
name = "main",
srcs = ["main.cpp"],
linkshared=True,
copts = ["-shared", "-fpic", "-fPIC"],
features = ["fully_static_link"],
)
main.cpp
int main()
{
return 1;
}
Other versions of the build file with similar results
cc_binary(
name = "main",
srcs = ["main.cpp"],
linkshared=True,
linkstatic=1,
linkopts = ["-static"]
)
cc_binary(
name = "main",
srcs = ["main.cpp"],
linkshared=True,
linkstatic=1,
linkopts = ["-static"],
features = ["fully_static_link"],
copts=["-fpic"],
)
TL;DR
Bazel will not compile a fully static binary in Ubuntu 20.04, GCC 9.3.0. I'm seeking to understand if the issue posted is related or if I don't understand something about static linking?

Related

Can't use linkopts when building libpqxx using Bazel

I am trying to use Bazel with libpqxx, which does not have native Bazel support. Rather than trying to write my own BUILD file, I am using rules_foreign_cc cmake() to translate the provided CMakeLists.txt, and this builds a library named pqxx and links a static library libpqxx-7.7.a. When I try to add this as a dependency to a cc_binary, it is able to see all the headers, but is not able to run the program.
When installed locally, gcc requires the libraries -lpqxx -lpq (the C++ and C bindings). Locally, all the commands work fine: For example: g++ -L/usr/local/lib -lpqxx -lpq foo.cpp where /usr/local/lib is where the library was installed. I cannot duplicate this behavior in Bazel.
I can see that there is a libpqxx-7.7.a file in bazel-bin, but adding the path from "$(bazel info bazel-bin)/workspace/libpqxx-7.7.a" throws a error: ld: library not found for -lpqxx.
Leaving the link options out produces
Undefined symbols for architecture arm64:
"_ASN1_STRING_get0_data", referenced from:
_pgtls_verify_peer_name_matches_certificate_guts in libpq.a(fe-secure-openssl.o)
"_ASN1_STRING_length", referenced from:
_pgtls_verify_peer_name_matches_certificate_guts in libpq.a(fe-secure-openssl.o)
"_BIO_clear_flags", referenced from:
_my_sock_write in libpq.a(fe-secure-openssl.o)
_my_sock_read in libpq.a(fe-secure-openssl.o)
which I believe is a linking error. I am new to C++, and am trying to translate the CMakeLists to work with Bazel. Where am I building my cmake wrong?
WORKSPACE
http_archive(
name = "libpqxx",
url = "https://github.com/jtv/libpqxx/archive/refs/heads/master.zip",
build_file_content = _ALL_CONTENT,
strip_prefix = "libpqxx-master",
)
BUILD
load("#rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
load("#rules_foreign_cc//foreign_cc:defs.bzl", "cmake")
cmake(
name = "pqxx",
cache_entries = {
"DPostgreSQL_ROOT=": "/Library/PostgreSQL/14",
"DSKIP_BUILD_TEST": "on"
},
lib_source = "#libpqxx//:all_srcs",
visibility = ["//visibility:public"],
out_static_libs = ["libpqxx-7.7.a"],
targets = ["pqxx"]
)
cc_binary(
name = "database_tester",
srcs = ["database_access.cpp"],
deps = [
":pqxx",
],
)

How to use glog with bazel?

I was able to install glog with:
brew install glog
Then I can successfully compile and use it using g++:
g++ src/main/main_logger.cc -std=c++17 -lglog
How can I do this with bazel?
I get this error:
fatal error: 'glog/logging.h' file not found
#include <glog/logging.h>
^~~~~~~~~~~~~~~~
1 error generated.
UPDATE:
Instead of installing and building glog locallay, I ended up referencing it as a git repo in the WORKSPACE file:
git_repository(
name = "glog",
remote = "https://github.com/google/glog.git",
tag = "v0.5.0",
)
Now I can depend on it in my cc_binary rules like this:
cc_binary(
name = "main_logger",
srcs = ["main_logger.cc"],
deps = [
"//src/lib:CPPLib",
"#com_github_gflags_gflags//:gflags",
"#glog",
],
)
Complete example here.
There is already a doc about to use glog within a project which uses the Bazel build tool. link
Then you can create a BUILD file, and use bazel build //src/main:main_logger to build it.
cc_binary(
name = "main_logger",
srcs = ["main_logger.cc"],
deps = ["#com_github_google_glog//:glog"],
)

Link archive to shared library with Bazel

Using Bazel, I'd like to link a position independent static archive directly to a shared library (not to the application using the shared library). Something like:
g++ -shared mylib.cpp archive.a -o libmylib.so
g++ mybin.cpp -lmylib -o mybin
Rationale: RedHat packages libelf as a static archive, that has some otherwise public symbols (e.g: elf_errmsg) marked as hidden: the archive must be linked to the module using it (in this case, the shared library): linking to the application is too late.
I tried:
Wrapping the archive in a cc_import rule
Adding the rule to the deps of the cc_library: doesn't work, archive gets linked to the app
Adding the rule to the srcs of the cc_library: doesn't work, archive gets linked to the app
Adding the archive file directly to the linkopts of the cc_library: almost works, but the archive gets linked to both the library and the binaries depending on it.
Renaming the archive to .lo or .pic.lo: doesn't work, archive gets linked to the app with -Wl,wholearchive
Adding alwayslink = True to the cc_import: doesn't work, archive gets linked to the app with -Wl,wholearchive
Something like this should work for what you're trying to do:
cc_binary(
name = "libmylib.so",
srcs = ["mylib.cpp", "archive.a"],
linkshared = True,
)
cc_library(
name = "mylib",
srcs = ["libmylib.so"],
hdrs = ["mylib.hpp"],
)
cc_binary(
name = "mybin",
srcs = ["mybin.cpp"],
deps = [":mylib"],
)
You can build a shared library (which is done as cc_binary(linkshared = True); this bit may not seem entirely intuitive) from your source and the library archive.
You can build a cc_library to use as a dependency of your other targets... and use that to build a cc_binary target.
In theory if this was just one time/place thing, you could probably shorten it like this (but it's more of a minimal length example):
cc_binary(
name = "libmylib.so",
srcs = ["mylib.cpp", "archive.a"],
linkshared = True,
)
cc_binary(
name = "mybin",
srcs = ["mybin.cpp", "mylib.hpp", ":libmylib.so"],
)

How to build openFrameworks as a shard library on macOS

I'm trying to build OF as a shared library (.so) in macOS.
I added the following to my app's config.make file.
APPNAME = myApp.so
PROJECT_LDFLAGS = -rdynamic -shared -undefined dynamic_lookup
PROJECT_OPTIMIZATION_CFLAGS_RELEASE = -O3
But when I build the project using make, it actually generates an Application file myApp.so.app which is not a shared library.
How can I properly build OF as a shared library in macOS?
I could successfully build OF as a shared library with the following:
APPNAME = myApp.so
PROJECT_CFLAGS = -Wall
PROJECT_LDFLAGS = -dynamiclib -Wl,-undefined -Wl,dynamic_lookup
PROJECT_OPTIMIZATION_CFLAGS_RELEASE = -O3

Linking with NS3 module with circular dependency to other library

I am trying to build custom NS3 module which depends on some static library. This static library depends on NS3 module.
Platform: Ubuntu 16.04 x64
Toolchain: GCC 5.4.0
I will refer to my custom NS3 module as mymodule
I will refer to the library which mymodule depends on as mylib
I will refer to the program which links with mymodule and mylib as myprog
wscript for mymodule:
def build(bld):
module = bld.create_ns3_module('mymodule', ['network'])
module.features = 'c cxx cxxstlib ns3module'
module.source = [
'model/mymodule.cc' ]
# Make a dependency to some other static lib:
bld.env.INCLUDES_MYLIB = [ "some/include/path" ]
bld.env.LIB_MYLIB = ['mylib']
bld.env.LIBPATH_MYLIB = [ "some/path" ]
module.use.append('MYLIB')
# Create a program which uses mymodule
p = bld.create_ns3_program('myprog', ['core', 'mymodule'])
p.source = 'prog.cpp'
headers = bld(features='ns3header')
headers.module = 'mymodule'
headers.source = ['model/mymodule.h']
When I do ./waf build it fails: LD cannot link myprog because mylib has unresolved symbols. This failure is actually expected because mylib and mymodule are codependent and should be linked in non-standard way.
Workarounds:
If I build myprog by hand and use -Wl,--start-group
-lns3.26-mymodule-debug -lmylib -Wl,--end-group it links perfectly fine and works as expected.
If I combine two static libs by hand (using ar -M script) and then run ./waf build it also works fine.
The question: How can I integrate one of the workarounds above into wscript?
it looks like a known problem with order of static libs inclusion. The behavior has changed in waf 1.9, due to this problem.
One workaround might be to use the linkflags attribute of program. You should prefer the use of STLIB_MYLIB and STLIBPATH_MYLIB as mylib is static. In waf 1.9 with he correct order of libs it might suffice.
Anyway, use -v to see the command line generated by waf, it might help !