Building libraries with bazel and hardcoding dependencies into them - gcc

Is it possible to hard code dependencies into the libraries build with bazel. The reason is that if I build somelib I can use it in the workspace but as soon as I copy the lib somewhere else I loose all dependencies (bazel cache). Witch creates a problem when I want to deploy the libraries into the system or install.
some_folder
|
thirdparty
|_WORKSPACE
|_somelib
| |_src
| |_ a.c
| |_ BUILD
| |_include
| |_a.h
|_include
|_ b.h

It sounds like you want to build a fully statically linked library. This can be done in Bazel by building the library using cc_binary with the linkshared attribute set to True. According to the documentation you also have to name your library libfoo.so or similar.
What enables the static library here is cc_binary's linkstatic attributes behavior. When True, which is the default, all dependencies that can be linked statically into the binary will be. Note that linkstatic does NOT behave the same on cc_library, see the documentation.
So, basically you want something like this in your BUILD file
cc_binary(
name = "libfoo.so",
srcs = [...],
hdrs = [...],
linkshared = 1,
#linkstatic = 1 # This is the default, you don't need to add this.
)
Good luck!

Related

NDK project build with multiple CMakeFiles.txt

My intent is to have prebuilt libprebuilt.so and libmylib.so built into the apk. My project is structured like this
|-mylib_prebuilts
| |-libprebuilt.so
| |-include_dir
| '-CMakeFiles.txt
|-mylib
| |-src
| '-CMakeFiles.txt
'-build.gradle
In the CMakeFiles.txt for mylib_prebuilts, I have the following.
add_library(prebuiltlib SHARED IMPORTED)
target_include_directories(prebuiltlib INTERFACE include_dir)
set_property(TARGET prebuiltlib PROPERTY IMPORTED_LOCATION libprebuilt.so)
In the CMakeFiles.txt for lib, I have the following
add_subdirectory(../mylib_prebuilts mylib_prebuilts)
add_library(mylib SHARED ${srcs})
target_link_libraries(mylib PUBLIC prebuiltlib)
The root gradle.build has the following
externalNativeBuild {
cmake {
version '3.18.1'
path 'mylib/CMakeLists.txt'
}
}
I cannot reach the prebuilt headers or library from mylib. I get "headers not found" error, or if I manually add the header path using include_directories(../mylib_prebuilts/include_dir), build cannot find symbols when linking.
Answering my own question with a solution I stumbled upon.
mylib_prebuilts/CMakeLists.txt has to contain the following changes.
Add GLOBAL keyword to add_library call.
Use absolute path instead
of relative for set_property call using ${MAKE_CURRENT_SOURCE_DIR}
variable
add_library(prebuiltlib SHARED IMPORTED GLOBAL)
target_include_directories(prebuiltlib INTERFACE include_dir)
set_property(TARGET prebuiltlib PROPERTY IMPORTED_LOCATION ${MAKE_CURRENT_SOURCE_DIR}/libprebuilt.so)

Issue with developing a multi-module Go workspace

My folder structure looks something like this... (say my git repo name is demorepo)
demorepo
|--directory1
|-- (no go.mod at this level)
|--module1
|--package1 --------->--------------->--------------------->----|
|--go.mod (github.com/demorepo/directory1/module1) |
|--go.sum |
|--module2 |
|--module3 |
|--directory2 |
|-- (no go.mod at this level) |
|--newmodule ------<------------<------------------<----------------|
Now, I want to use a function defined in "package1" in my "newmodule"
When I hit
go get <repo_address>/directort1/module1/package1 at "new_module"
it says ....
github.com/<repo>#upgrade found (v0.0.0-20211215055943-92e412ad4a12), but does not contain package github.com/<repo>/directory1/module1/package1
There is a proposal for a Go Workspace File for Go 1.18 which should simplify this task.
Meanwhile, you can use the replace directive in your go.mod file to refer to a module located on a local filesystem.
demorepo/directory1/module1/go.mod:
module github.com/<repo>/directory1/module1
demorepo/directory2/newmodule/go.mod:
module github.com/<repo>/directory2/newmodule
replace github.com/<repo>/directory1/module1 => ../../directory1/module1
Now you can import github.com/<repo>/directory1/module1/package1 in newmodule normally and it'll refer to the local module1.
You might not want the replace directive in the go.mod file itself, and instead make a copy of it e.g. go.mod.local and use it when building your project: go build -modfile go.mod.local . (can also add *.local to .gitignore).
Approach :
If you want to use module1 inside newModule then you should make one new repo for module1 put your logic there push it in github. please make sure you should use appropriate version for the library.
import it as a library and it will work.
Also refer the official docs of module dependency and also check root level dependency.
Official docs : https://go.dev/blog/using-go-modules

Include <headers.h> installed in non standard location

I'm currently working with a third party library, which has headers declared using angular brackets, like a standard library :
#include <header.h>
However, these headers are installed in a non standard place, something like /opt/company/software/version/part_software/include
With a more traditional builder like MAKE, I can just use CXXFLAGS to indicate to g++ to look in this folder too for libraries, which finally comes down to pass a -I/opt/company/software/version/part_software/include option to g++.
When trying to do the same thing in bazel, using copts = [ "-I/opt/company/software/version/part_software/include" ], I get a "path outside of the execution root" error.
It's my understanding that bazel don't like the place where the lib is installed because the build needs to be reproducible, and including a library located outside the execution root violate this constraint.
A ugly hack I've come with is to create symbolic link of the headers in /usr/local/include, and use copts = [ "-I/usr/local/include" ] in the bazel build. However, I find this approach very hacky, and I'd like to find a more bazely approach to the problem.
Note : I can't install the program during the bazel build, as it uses a closed installer on which I have no control over. This installer can't be run in the bazel's sandboxed environment, as it needs to write on certain paths not accessible within the environment.
So, it turns out that the bazelesque way of including a third part library is simply to create package encapsulating the library.
Thanks to this useful discussion, I've managed to create a package with my third party library.
First we need a BUILD file, here named package_name.BUILD
package(
default_visibility = ["//visibility:public"]
)
cc_library(
name = "third_party_lib_name", #name to reference the third party library in other BUILD files
srcs = [
"external/soft/lib/some_lib.so", #.so files to include in the lib
"software/lib/os/arch/lib_some_plugin.so",
],
hdrs = glob([ # the glob takes all the headers needed
"software/include/**/*.h",
"software/include/**/*.hpp",
]),
includes = ["software/include/"], # Specify which files are included when we use the library
)
Now we need to reference the lib a a submodule in the WORKSPACE file :
new_local_repository(
name = "package_name",
path = "opt/company/software/version",
# build_file: path to the BUILD file, here in the same directory that the main WORKSPACE one
build_file = __workspace_dir__ + "/package_name.BUILD",
)
Now, instead of using copt to references the needed headers, I'm just adding a line to the deps of the cc_rule when needed, e.g :
cc_library(
name="some_internal_lib",
srcs = ["some_internal_lib.cc"],
deps = [
"#package_name//:third_party_lib_name", #referencing the third party lib
],
)

Creating a CMakeLists.txt with header and mains

I have divided my program in 3 folders: build, include, and src.
Build is where I want all the files created from the Makefile to go, include contains a "file.h", and src contains a "file.c" and "main.c".
I have written this in the CMakeLists.txt file:
cmake_minimum_required (VERSION 3.5.1)
project(Listas_interlazadas)
include_directories(${include})
add_executable(ejec
src/main.c
src/listas.c
include/listas.h
)
Nonetheless, I believe I should somehow include the src folder. Also, how do I send all files to the build folder? From the terminal, right?
Thanks.
Your code need some minor reworks.
The command include_directories must point to an valid path
Add header files only in case they are not included in any of your source files
Assume the following structure of your project:
project
+--source
| +--CMakeLists.txt
| +--src
| | +--main.c
| | +--listas.c
| +--include
| +--listas.h
+--build
Reworked CMakeLists.txt
cmake_minimum_required (VERSION 3.5.1)
project(Listas_interlazadas)
include_directories(include)
add_executable(ejec
src/main.c
src/listas.c
)
Back to your questions:
Add the sources: You already inserted the required source files. See add_executable.
Copy sources to build folder: This is not necessary.
To build your project, you have to run cmake and make (or nmake on windows).
Steps:
Open a command shell
Move to the build folder
Run: cmake ../source
Run: make
Some important parts of a CMakeLists.txt

CMake Hierarchical Project Management Without Abusing Libraries

I have a project where there's only a handful of logical groupings for generating static libraries. However for convenience I want to have the library's source code to be managed with more granular folders.
Currently the only way I know to do this in CMake without having a library for each folder is to just list files as you would normally in with their relative paths:
add_library(SystemAbstraction STATIC "Some/Path/File.cpp")
However I can see this getting unwieldy as the project grows in size with all the different paths.
I tried to see if I could have a CMakeLists.txt in each folder and just use a variable in the base CMakeLists.txt when adding library dependencies. But it seems that add_subdirectory doesn't also import variables?
For expanding the scope of a variable inside a subdirectory, use the PARENT_SCOPE option of set. For example, you can test that if you have
# CMakeLists.txt
set(SRCS main.c)
add_subdirectory(foo)
message(${SRCS})
in the root directory and
# foo/CMakeLists.txt
set(SRCS ${SRCS} foo.c PARENT_SCOPE)
in a subdirectory then it will print main.c foo.c, i.e., the variable is correctly imported into the base CMakeLists.txt.
An option would be to use the object library feature of CMake. You still can but doesn't need to organise your CMake script into subdirectories:
add_library(lib1 OBJECT <srcs>)
add_library(lib2 OBJECT <srcs>)
...
add_library(mainlib $<TARGET_OBJECTS:lib1> $<TARGET_OBJECTS:lib2>)
You can set different compile flags for each object library:
target_include_directories(lib1 PRIVATE incl-dir-for-lib1)
target_compile_definitions(lib2 PRIVATE def-for-lib2)
You still need to set link libraries on your main library:
target_link_libraries(mainlib PRIVATE deps-of-lib1 deps-of-lib2)
Related documentation: Object Libraries

Resources