How to build static library .a for ARM using cross compiler? - gcc

I was trying to compile statically cpp-netlib and rpclib for ARM device.(Same as ZEDboard)
Everything i did is changed the compiler and system settings in CMakeLists.txt file.
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_SYSROOT /home/a/buildroot-2018.05/output/host/arm-buildroot-linux-uclibcgnueabihf/sysroot/)
set(tools /home/a/buildroot-2018.05/output/host/bin/)
set(CMAKE_C_COMPILER ${tools}arm-buildroot-linux-uclibcgnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${tools}arm-buildroot-linux-uclibcgnueabihf-g++)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
After Makefile is created by cmake i ran make and no output has been produced. As i understand build directories should appear.
For the rpclib things went better. It has compiled the librpc.a file but unftunately its not linking to my program.
arm-buildroot-linux-uclibcgnueabihf-g++ -I/home/a/rpclib/include/ -Xlinker -static /home/a/rpclib/librpc.a main.cpp
produces this output:
/home/a/buildroot-2018.05/output/host/lib/gcc/arm-buildroot-linux-uclibcgnueabihf/6.4.0/../../../../arm-buildroot-linux-uclibcgnueabihf/bin/ld: cannot find -lgcc_s
/home/a/buildroot-2018.05/output/host/lib/gcc/arm-buildroot-linux-uclibcgnueabihf/6.4.0/../../../../arm-buildroot-linux-uclibcgnueabihf/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
but there is gcc_s in the sysroot directory.
~/buildroot-2018.05/output/host/arm-buildroot-linux-uclibcgnueabihf$ find ./ -name *gcc_s*
./sysroot/lib/libgcc_s.so
./sysroot/lib/libgcc_s.so.1
./sysroot/usr/include/boost/asio/detail/gcc_sync_fenced_block.hpp
./sysroot/usr/include/boost/atomic/detail/caps_gcc_sync.hpp
./sysroot/usr/include/boost/atomic/detail/ops_gcc_sync.hpp
./sysroot/usr/include/boost/atomic/detail/ops_gcc_sparc.hpp
./sysroot/usr/include/boost/atomic/detail/caps_gcc_sparc.hpp
./sysroot/usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp
./lib/libgcc_s.so
./lib/libgcc_s.so.1
I guess i am missing something important about cross-compilation.
So basically i have 3 questions:
Can you suggest some resources about cross-compilation for embdedd devices?
How to compile cpp-netlib?
How to link already compiled librpc?

Actually buildroot supports building static libraries.
Steps to build a custom library using buildroot:
Create a folder inside buildroot/package folder with the name of target library.
e.g. my path looks like this /home/a/buildroot-2018.05/package/rpclib
Create Config.in file in target library dir with the needed parameters which can be checked in buildroot manual or better
Create [package-name].mk
Then add entry in /buildroot/package/Config.in
Then package can be marked for installation in menuconfig/target pacckages
My Config.in file for rpclib
config BR2_PACKAGE_RPCLIB
bool "rpclib"
depends on BR2_INSTALL_LIBSTDCPP
depends on BR2_USE_WCHAR
help
rpclib is a modern C++ msgpack-RPC server and client library
http://rpclib.net
My rpclib.mk file
RPCLIB_VERSION = v2.2.1
RPCLIB_SITE = $(call github,rpclib,rpclib,$(RPCLIB_VERSION))
RPCLIB_INSTALL_STAGING = YES
RPCLIB_INSTALL_TARGET = NO
RPCLIB_CONF_OPTS = -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF
$(eval $(cmake-package))
And entry in Config.in in the buildroot/packages dir
source "package/rpclib/Config.in"
After executing make i received
./output/host/arm-buildroot-linux-uclibcgnueabihf/sysroot/usr/lib/librpc.a

Working in my little beatle (https://gitlab.com/melviso1/beatle) I have a custom makefile for building rpclib without using cmake stuff (I apologize but I really hate cmake and similar tools). Maybe that can help.
Put it in the root of rpclib for building, clean or install. Please review tabs in the following script, because my pasting here can make some loses.
I used this to compile rpclib inside arm. For cross-compiling you could edit and change build tools.
CXXFLAGS=-std=c++0x -O3 -pthread -DASIO_STANDALONE -DRPCLIB_ASIO=clmdep_asio -DRPCLIB_FMT=clmdep_fmt -DRPCLIB_MSGPACK=clmdep_msgpack -Wall
INCLUDE=-Iinclude -I./dependencies/include
OBJS=obj/format.o obj/posix.o obj/client.o obj/client_error.o obj/response.o obj/server_session.o obj/dispatcher.o obj/optional.o obj/rpc_error.o obj/server.o obj/this_handler.o obj/this_server.o obj/this_session.o
all: obj librpc.a
obj:
mkdir -p obj
librpc.a: $(OBJS)
ar -r -s librpc.a $(OBJS)
obj/format.o: dependencies/src/format.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./dependencies/src/format.cc -o obj/format.o
obj/posix.o: dependencies/src/posix.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./dependencies/src/posix.cc -o obj/posix.o
obj/client.o: lib/rpc/client.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./lib/rpc/client.cc -o obj/client.o
obj/client_error.o: lib/rpc/detail/client_error.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./lib/rpc/detail/client_error.cc -o obj/client_error.o
obj/response.o: lib/rpc/detail/response.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./lib/rpc/detail/response.cc -o obj/response.o
obj/server_session.o: lib/rpc/detail/server_session.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./lib/rpc/detail/server_session.cc -o obj/server_session.o
obj/dispatcher.o: lib/rpc/dispatcher.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./lib/rpc/dispatcher.cc -o obj/dispatcher.o
obj/optional.o: lib/rpc/nonstd/optional.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
obj/rpc_error.o: lib/rpc/rpc_error.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
obj/server.o: lib/rpc/server.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
obj/this_handler.o: ./lib/rpc/this_handler.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
obj/this_server.o: lib/rpc/this_server.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
obj/this_session.o: ./lib/rpc/this_session.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
install:
cp -rf include/rpc /usr/local/include/
cp librpc.a /usr/local/lib/
uninstall:
rm -rf /usr/local/include/rpc
rm /usr/local/lib/librpc.a
clean:
rm -f librpc.a
rm -f obj/*
.PHONY: obj clean install uninstall`

Related

Makefile dependency rules for multiple source-object compilation

I apologize if this is a somewhat noobish question, I have been searching for a while and haven't found the answer.
I am new to makefiles, and am trying to create one which compiles multiple source files in various directories into object files in a single directory and then link them.
It works, but it always recompiles all the files even if I haven't changed them. To my understanding, it should only do this if the dependencies are older than the targets. What am I doing wrong?
Here is my makefile:
CC = mpic++
CCU = nvcc
ARCH = -arch=sm_52
SOURCEDIR = ./source
SOLVERDIR = $(SOURCEDIR)/solvers
OBJECTDIR = ./bin
INCLUDE = -I./include -I/home/alexander/.openmpi/include -I/usr/local/cuda-7.5/include
LIBRARY = -L/usr/local/cuda-7.5/lib64 -lcublas -lcudart
OUT = cgsolve
CDEPS = $(OBJECTDIR)/main.o $(OBJECTDIR)/timer.o $(OBJECTDIR)/cgMPIFuncs.o
compileC: $(CDEPS)
$(CC) $(INCLUDE) -c $(SOURCEDIR)/main.cpp -o $(OBJECTDIR)/main.o
$(CC) $(INCLUDE) -c $(SOURCEDIR)/timer.cpp -o $(OBJECTDIR)/timer.o
$(CC) $(INCLUDE) -c $(SOURCEDIR)/cgMPIFuncs.cpp -o $(OBJECTDIR)/cgMPIFuncs.o
CUDEPS = $(OBJECTDIR)/BiCGStab.o $(OBJECTDIR)/CG.o $(OBJECTDIR)/solverUtil.o $(OBJECTDIR)/cudaKernels.o
compileCU: $(CUDEPS)
$(CCU) $(ARCH) $(INCLUDE) -c $(SOLVERDIR)/BiCGStab.cu -o $(OBJECTDIR)/BiCGStab.o
$(CCU) $(ARCH) $(INCLUDE) -c $(SOLVERDIR)/CG.cu -o $(OBJECTDIR)/CG.o
$(CCU) $(ARCH) $(INCLUDE) -c $(SOURCEDIR)/solverUtil.cu -o $(OBJECTDIR)/solverUtil.o
$(CCU) $(ARCH) $(INCLUDE) -c $(SOURCEDIR)/cudaKernels.cu -o $(OBJECTDIR)/cudaKernels.o
OBJDEPS = $(OBJECTDIR)/main.o $(OBJECTDIR)/BiCGStab.o $(OBJECTDIR)/CG.o $(OBJECTDIR)/solverUtil.o $(OBJECTDIR)/cudaKernels.o $(OBJECTDIR)/timer.o $(OBJECTDIR)/cgMPIFuncs.o
build:
$(CC) $(OBJDEPS) $(LIBRARY) -o $(OUT)
all: compileC compileCU build
And again, sorry if this is a repeat or something. I haven't been able to find a previous version of this question. Thanks for the help!
Instead of setting rules explicitly altogether, please try pattern-rule like below, also it's better to add OBJDEPS as pre-requisite for build target (then no need for compileC and compileCU, unless you want to keep those targets)
compileC: $(CDEPS)
compileCU: $(CUDEPS)
build: $(OBJDEPS)
$(CC) $^ $(LIBRARY) -o $(OUT)
$(OBJECTDIR)/%.o : $(SOURCEDIR)/%.cpp
$(CC) $(INCLUDE) -c $^ -o $#
$(OBJECTDIR)/%.o : $(SOLVERDIR)/%.cu
$(CCU) $(ARCH) $(INCLUDE) -c $^ -o $#

Makefile: How write a rule that is only executed when a certain shared object library doesn't exist?

I am trying to write a rule, which should only execute if a certain shared object library doesn't exist
$(OUTDIR)/libv8-$(ARCH).so: v8
v8: # to be able to build V8 only with "make v8"
cd V8; bash V8Update.sh
However, V8Update.sh is executed every time. Here is the full Makefile:
CC=g++
V8INCLUDEDIR=V8/build/v8/include
CFLAGS=-c -Wall -std=c++0x -fPIC -I$(V8INCLUDEDIR) -I/usr/include -I/usr/include/c++/4.6 \
-I/usr/include/c++/4.6/backward -I/usr/include/c++/4.6/x86_64-linux-gnu -I/usr/include/x86_64-linux-gnu \
-I/usr/lib/gcc/x86_64-linux-gnu/4.6/include -I/usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed \
-I/usr/local/include -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include/
DEPS=ProxyTypes.h $(V8INCLUDEDIR)/v8.h $(V8INCLUDEDIR)/v8-debug.h $(V8INCLUDEDIR)/v8stdint.h
ARCH=x64 # TODO: Add support for building 32-bit libraries.
LDFLAGS=-shared -lglib-2.0 -L/usr/lib/x86_64-linux-gnu/ #-Wl,--no-undefined
SOURCES=Exports.cpp FunctionTemplateProxy.cpp HandleProxy.cpp ObjectTemplateProxy.cpp Utilities.cpp V8EngineProxy.cpp \
ValueProxy.cpp
OBJECTS=$(patsubst %,$(OUTDIR)/%,$(SOURCES:.cpp=.o))
LIBRARY=libV8_Net_Proxy.so
.PHONY: all v8 release debug makeoutdir clean copybin
all: debug copybin
v8: # to be able to build V8 only with "make v8"
cd V8; bash V8Update.sh
release: OUTDIR=bin/Release
debug: OUTDIR=bin/Debug
release debug:
$(MAKE) -S makeoutdir $(LIBRARY) OUTDIR=$(OUTDIR)
makeoutdir:
mkdir -p $(OUTDIR)
clean:
rm bin/ -rf
# rm V8/build -rf
copybin:
cp -a bin/Debug/*.so ../bin/Debug
$(LIBRARY): $(OUTDIR)/libv8-$(ARCH).so $(OBJECTS)
$(CC) $(LDFLAGS) -lv8-$(ARCH) -L$(OUTDIR) -o $(patsubst %,$(OUTDIR)/%,$#) $(OBJECTS)
$(OUTDIR)/libv8-$(ARCH).so: v8
$(OUTDIR)/%.o: %.cpp $(DEPS)
$(CC) $(CFLAGS) -o $# $<
What am I doing wrong here?
It should be
v8: $(OUTDIR)/libv8-$(ARCH).so
$(OUTDIR)/libv8-$(ARCH).so:
cd V8; bash V8Update.sh
You can't depend on phony target - it will be executed every time (and that is a feature, btw).

What's the proper lib variable for a makefile?

Running into trouble with libraries in makefiles again. Every time I try to get back into C make gives me a pain with libs.
make -pf /dev/null says the correct vars should be LDLIBS and LOADLIBES but the following doesn't alter the run command at all:
LOADLIBES=testing
LDFLAGS=testing
LDLIBS=testing
Needless to say this gives me errors because the -L flags don't end up in the command. Anyone know what's going on?
Full makefile below (Derivitave of Z Shaw's makefile)
OPTLIBS=$(xml2-config --libs)
OPTFLAGS=$(xml2-config --cflags)
STD=c99
CFLAGS=-std=$(STD) -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS)
LDLIBS=-ldl $(OPTLIBS)
PREFIX?=/usr/local
SOURCES=$(wildcard src/**/*.c src/*.c)
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
TEST_SRC=$(wildcard tests/*_tests.c)
TESTS=$(patsubst %.c,%,$(TEST_SRC))
TARGET=build/lib.a
SO_TARGET=$(patsubst %.a,%.so,$(TARGET))
# The Target Build
all: cls $(TARGET) $(SO_TARGET) tests
dev: CFLAGS=-std=$(STD) -g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)
dev: all
$(TARGET): CFLAGS += -fPIC
$(TARGET): build $(OBJECTS)
ar rcs $# $(OBJECTS)
ranlib $#
$(SO_TARGET): $(TARGET) $(OBJECTS)
$(CC) -shared -o $# $(OBJECTS)
build:
#mkdir -p build
#mkdir -p bin
# The Unit Tests
$(TESTS): $(TARGET)
.PHONY: tests
tests: LDLIBS += $(TARGET)
tests: $(TESTS)
sh ./tests/runtests.sh
valgrind:
VALGRIND="valgrind --log-file=/tmp/valgrind-%p.log" $(MAKE)
# The Cleaner
clean: cls
rm -rf build $(OBJECTS) $(TESTS)
rm -f tests/tests.log
find . -name "*.gc*" -exec rm {} \;
rm -rf `find . -name "*.dSYM" -print`
# The Install
install: all
install -d $(DESTDIR)/$(PREFIX)/lib/
install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/
# The Checker
BADFUNCS='[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy|a?sn?printf|byte_)'
check:
#echo Files with potentially dangerous functions.
#egrep $(BADFUNCS) $(SOURCES) || true
# Clear screen for unspammy terminals
cls:
ifdef TERM
clear
endif
You aren't using LDFLAGS, etc in your link command. Make that something along the lines of:
$(SO_TARGET): $(TARGET) $(OBJECTS)
$(CC) -shared $(LDFLAGS) -o $# $(OBJECTS) $(LDLIBS)
It tells the linker to link the dl library, which is located at /usr/lib/libdl.so. -l is the switch to add a library, dl is the name of it (without the lib prefix or .so extension).
This library includes functions for dynamically loading shared libraries.

How to include from directory?

I am trying to add a project's (call it b) code to a different project(call it a). Both projects are compile and run separately. I just copied the folder of project b into project a's folder. In project a's Makefile, I added the lines to compile project b with it. It compiles fine. Now I want to use b's code. But when I try to #include "/bfolder/somefile.h", it cannot find the file. What am I missing about this? If I can just #include "somefileinsamedirectory.h", why can't I do #include "/bfolder/somefile.h"?`
This is a 's Makefile that I have edited to include the irobot_driver code.
INCLUDE = -I/usr/X11R6/include -I/home/sterling/irobot_driver
CC=g++
CFLAGS=-w -D LINUX -fpermissive
CFLAGS_R= -w -D LINUX -O3 -fpermissive
CFLAGS_D=-w -D LINUX -fpermissive
OBJ= obj
OBJ_DEBUG= obj_debug
OBJDIR= release
SRCDIR= src
LDFLAGS= -L/usr/X11R6/lib$(LIBSELECT) -lGL -lfltk -lfltk_gl -lXext -lX11 -lglut -lGLU -lfltk_images
SOURCES_RAW=codeprofiler.cpp gametimer.cpp timer.cpp timeprofile.cpp vector4.cpp matrix.cpp agent.cpp agentcontroller.cpp dummy.cpp evader.cpp pursuer.cpp goal.cpp player.cpp graphdata.cpp graph.cpp cubiccoefs.cpp segment.cpp trajectory.cpp anode.cpp arrayvector4.cpp color.cpp drawcomponent.cpp drawcontroller.cpp flags.cpp global.cpp map_analyzer.cpp minheap.cpp node.cpp quadtree.cpp queue.cpp results.cpp sensor.cpp settings.cpp utility.cpp world.cpp gui.cpp main.cpp logger.cpp parameters.cpp counter.cpp polygon.cpp line.cpp
TARGET:= pursuit_evasion
TARGETD:= pursuit_evasion_d
TARGETP:= pursuit_evasion_p
TARGETW32:= pursuit_evasion_w32
OBJECTS:=$(SOURCES_RAW:.cpp=.o)
OBJECTS:=$(patsubst %.o,$(OBJDIR)/%.o, $(OBJECTS))
SOURCES:=$(SOURCES_RAW)
SOURCES:=$(patsubst %.cpp,$(SRCDIR)/%.cpp, $(SOURCES))
OBJ_DEBUG:=$(SOURCES_RAW:.cpp=.o)
OBJ_DEBUG:=$(patsubst %.o,debug/%.o, $(OBJ_DEBUG))
OBJECTS_P:=$(SOURCES_RAW:.cpp=.o)
OBJECTS_P:=$(patsubst %.o,profile/%.o, $(OBJECTS_P))
OBJDIR=obj
all: $(TARGET)
#--- Release
$(TARGET): $(OBJECTS)
$(CC) -w -D LINUX $(INCLUDE) $^ -o $# $(LDFLAGS)
cd /home/sterling/irobot_driver; sudo make -j2
release/%.o: src/%.cpp
$(CC) -c $< $(CFLAGS_R) -o $#
#--- Debug
debug: $(TARGETD)
$(TARGETD): $(OBJ_DEBUG)
$(CC) -w -D LINUX $(INCLUDE) $^ -o $# $(LDFLAGS)
cd /home/sterling/irobot_driver; sudo make -j2
debug/%.o: src/%.cpp
$(CC) -c -g $< $(CFLAGS)-o $#
#-- Profile
profile: $(TARGETP)
$(TARGETP): $(OBJECTS_P)
$(CC) -w -g -pg -D LINUX $(INCLUDE) $^ -o $# $(LDFLAGS)
profile/%.o: src/%.cpp
$(CC) -c -g -pg $< $(CFLAGS)-o $#
win32: $(TARGETW32)
$(TARGETW32): $(OBJECTS)
$(CC) -w -D WIN32 $(INCLUDE_W32) $^ -o $# $(LDFLAGS)
.PHONY : clean
clean:
rm -f release/*.o
rm -f debug/*.o
rm -f profile/*.o
rm -f $(TARGET) $(TARGETD) $(TARGETP)
cd /home/sterling/irobot_driver; make clean;
The #include "/the/whole/path/to/a/file" that works is -
#include "/home/sterling/irobot_driver/robot_driver_agent.h"
You can, but when you declare the path starting with /some/path/to/file.h it's going to really look for the file at /some/path/to/file.h. If instead you want the bfolder/somefile.h, remove the / from the beginning.
Also, in general, if b is a library that you want to use, it is best to keep it in whatever folder it resides, and include and link using the -I, -L and -l options of gcc, or similar options of other compilers. This way, if you update b you don't need to copy it to every project that uses it.
Try
#include "bfolder/somefile.h"
You are including a leading slash in "/bfolder/somefile.h", which means /bfolder would be in the root directory.
#include "/bfolder/..." would be implying that bfolder is in the root directory of your computer's file system. If bfolder is in the same directory as your source code, then you would just want #include "bfolder/somefile.h"

Unable to find reference to std library math function inside library

I've got several programs that use shared libraries. Those shared libraries in turn use various standard C libraries. ie
Program A and Program B both use Shared Library S. Shared Library S uses std C math. I want to be able to statically link Shared Library S against the standard library, and then statically link Programs A and B against S so that I don't have to be dragging around the library files, because these programs are going to be running on an embedded system running BusyBox 0.61. However, when I try to statically link the programs against Shared Library S, I get an error message from GCC stating :
../lib/libgainscalecalc.a(gainscalecalc.): In function 'float2gs':
[path to my C file].c:73: undefined reference to 'log'
Can somebody please help me out ? The make commands I'm using are below :
CFLAGS += -Wall -g -W
INCFLAGS = -I$(CROSS_INCLUDE)/usr/include
LIBFLAGS += -L$(CROSS_LIB)/usr/lib -lm
gainscalecalc_static.o: gainscalecalc.c
$(CC) $(CFLAGS) -c $< -I. $(INCFLAGS) -o $#
gainscalecalc_dynamic.o: gainscalecalc.c
$(CC) $(CFLAGS) -fPIC -c $< -o $#
all: staticlib dynamiclib static_driver dynamic_driver
clean:
$(RM) *.o *.a *.so *~ driver core $(OBJDIR)
static_driver: driver.c staticlib
$(CC) $(CFLAGS) -static driver.c $(INCFLAGS) $(LIBFLAGS) -I. -L. -lgainscalecalc -o $#
dynamic_driver: driver.c dynamiclib
$(CC) $(CFLAGS) driver.c -o $# -L. -lgainscalecalc
staticlib: gainscalecalc_static.o
$(AR) $(ARFLAGS) libgainscalecalc.a gainscalecalc_static.o
$(RANLIB) libgainscalecalc.a
chmod 777 libgainscalecalc.a
dynamiclib: gainscalecalc_dynamic.o
$(CC) -shared -o libgainscalecalc.so gainscalecalc_dynamic.o
chmod 777 libgainscalecalc.so
Edit: Linking against the shared libraries compiles fine, I just haven't tested them out yet
Put the $(LIBFLAGS) after lgainscalecalc.
The linker command line is position dependent. Placing the -lm after your library will cause the linker to use libm.a to resolve references your library uses.

Resources