SCONS env.Library() does not get the expected environment compilation flags - scons

I'm running the following problem:
we have a large project (inherited from other company) compiling many sub-mules of SW.The contruction of the FW is sub-divided in several SConscripts
that we invoke from the main SConstruct. The point is that all the submodules share the same compilation flags and
defines.
I intended to solve this with the following solution:
In the main entry point , the SConstruct we define certain compilation options :
COMPILER_FLAGS = '-g \
-O3 \
-fshort-double \
-gdwarf-2 \
-Wall \
-W \
-Werror-implicit-function-declaration \
-Wno-unused-variable \
-Wno-empty-body \
-Wbad-function-cast \
-Wstrict-prototypes \
-Wmissing-noreturn \
-Wnested-externs \
-fno-builtin \
-Wno-unused-parameter \
-Wno-pointer-to-int-cast \
..........
This COMPILER_FLAGS are present the Construction environment which is passed to each Sconscript as argument
Then inside each Sconscript I make a clone of the environment and modify some of the options for each submodule
*SConstruct
log_path = os.path.join('../../CDD/LogPrint/Build/logprint.SC')
objects += SConscript(log_path, exports='env', variant_dir=log_build_dir, duplicate=1)
dbg_exe = env.Program(dbg_path, objects)
*logprint.SC
\#Customize Compilation options for this component
own_env = env.Clone()
own_env['COMPILER_FLAGS'] += '-O0 '
\# COMPILE SOURCE FILES
objects += own_env.Library(sources)
\# RETURN
Return('objects')
The point is that when I compile (and build a Library) for the logprint submodule I don't see the own_env extended
compiled Flags. I still see in the compilation command line printed the initial env options inherited from the main SConstruct file.
Any reason why this may be happening? Is there any top level SCONS option/configuration setting this behaviour?
Let me also highlight that I probed this concept of env.Clone in a new small project from the scratch and there it
works. So I wonder is some top SCONS configuration might be blocking the own_env.Library behaviour I want in the 'large'
project.

The following should do what I believe you're trying to do.
SConstruct
env=Environment()
env['CCFLAGS'] ='-g -O3 -fshort-double -gdwarf-2 -Wall -W -Werror-implicit-function-declaration -Wno-unused-variable -Wno-empty-body -Wbad-function-cast -Wstrict-prototypes -Wmissing-noreturn -Wnested-externs -fno-builtin -Wno-unused-parameter -Wno-pointer-to-int-cast'
log_path = os.path.join('../../CDD/LogPrint/Build/logprint.SC')
objects = SConscript(log_path, exports='env', variant_dir=log_build_dir, duplicate=1)
dbg_exe = env.Program(dbg_path, objects)
SConscript
#Customize Compilation options for this component
own_env = env.Clone()
own_env.Append('CCFLAGS' = '-O0 ')
# COMPILE SOURCE FILES
objects = own_env.Library(sources)
# RETURN
Return('objects')

Related

Linking issue in Cross Compilation for arm in linux using aarch64-linux-gnu-

I got an error when try to link (-aarch64-linux-gnu-ld) (the script containing the Makefile was downloaded from https://github.com/Icenowy/aw-el2-barebone). Error is "aarch64-linux-gnu-ld: Error: unable to disambiguate: -nostartfiles (did you mean --nostartfiles ?)
make: *** [Makefile:31: el2-bb.elf] Error 1" How to recode the line 31? of the Makefile
CROSS_COMPILE = /usr/bin/aarch64-linux-gnu-
DEBUG = 1
CC = $(CROSS_COMPILE)gcc
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
INCLUDES = -I ./include -I ./uboot-headers -ffreestanding
DEFINES = -DSOC_HEADER="\"h6.h\""
ifneq ($(DEBUG),1)
DEFINES += -DNDEBUG
endif
ASFLAGS = $(INCLUDES) $(DEFINES) -D__ASSEMBLY__
CFLAGS = $(INCLUDES) $(DEFINES) -O2
LDSCRIPT = ldscripts/a64.ld
LDSCRIPTS = ldscripts/a64.ld ldscripts/common.ld
LDFLAGS = -nostdlib -nostartfiles -static -T $(LDSCRIPT)
OBJS = start.o init.o uart.o stack.o exceptions.o exception_funcs.o panic.o pgtables.o trapped_funcs.o
all: el2-bb.bin
el2-bb.elf: $(OBJS) $(LDSCRIPTS)
$(LD) $(LDFLAGS) $(OBJS) -o $#
el2-bb.bin: el2-bb.elf
$(OBJCOPY) -O binary $< $#
.PHONY: clean
clean:
rm -f el2-bb.* *.o
-nostartfiles is a gcc option but not an ld option.
If you use gcc to invoke the linker (say with LD=gcc in your Makefile) for making a standalone program that does not use standard startup files, you should use -nostartfiles because gcc links the startup files by default and -nostartfiles disables this.
ld doesn't links any startup files by default, so there is no option to disable linking them. You always pass startup files explicitly to ld. If you don't want startup files, just don't pass them to ld.
In order to see what startup files on your system are create an empty C program:
int main(){}
and compile it:
gcc -c empty.c
gcc -v empty.o
You are likely to see an invocation of ld (or perhaps of collect2, which calls ld) with a long, long list of options and object files.
Now run
gcc -nostartfiles -v empty.o
The .o files are now gone. That's exactly what -nostartfiles does.
When you invoke ld empty.o, these files and options are not there to begin with. In order to make a working program for say a Linux system, you need to pass most of them to ld explicitly. If you are building a program for something other system, you may not need some or all of them. So just don't pass them in.

Configuring Makefile to produce a .a library instead of a .lib

I'm trying to compile a C library in a Linux Ubuntu environment (and that will be used by a Embedded Linux program), but when I do a make on it, I get a .lib instead of a .a file even thought it seems that there is no place in the Makefile that commands such a change (a would expect that compiling a library in Ubuntu would produce a .a file by default!).
What follows is the Makefile being used fro this library (the result now being calculos.lib):
Makefile
# ----------------------------------------------------------------------------
# Name of the ARM GCC cross compiler & archiver
# ----------------------------------------------------------------------------
ARM_TOOLCHAIN_PREFIX = arm-arago-linux-gnueabi-
ARM_TOOLCHAIN_PATH = /re8k/linux-devkit
ARM_CC := $(ARM_TOOLCHAIN_PATH)/bin/$(ARM_TOOLCHAIN_PREFIX)gcc
ARM_AR := $(ARM_TOOLCHAIN_PATH)/bin/$(ARM_TOOLCHAIN_PREFIX)ar
# Get any compiler flags from the environment
ARM_CFLAGS = $(CFLAGS)
ARM_CFLAGS += -std=gnu99 \
-Wdeclaration-after-statement -Wall -Wno-trigraphs \
-fno-strict-aliasing -fno-common -fno-omit-frame-pointer \
-c -O3
ARM_LDFLAGS = $(LDFLAGS)
ARM_LDFLAGS+=-lm -lpthread
ARM_ARFLAGS = rcs
# ----------------------------------------------------------------------------
# Name of the DSP C6RUN compiler & archiver
# TI C6RunLib Frontend (if path variable provided, use it, otherwise assume
# the tools are in the path)
# ----------------------------------------------------------------------------
C6RUN_TOOLCHAIN_PREFIX = c6runlib-
C6RUN_TOOLCHAIN_PATH = $(ARM_TOOLCHAIN_PATH)/c6run
C6RUN_CC := $(C6RUN_TOOLCHAIN_PATH)/bin/$(C6RUN_TOOLCHAIN_PREFIX)cc
C6RUN_AR := $(C6RUN_TOOLCHAIN_PATH)/bin/$(C6RUN_TOOLCHAIN_PREFIX)ar
C6RUN_CFLAGS = -c -mt -O3
C6RUN_ARFLAGS = rcs
# ----------------------------------------------------------------------------
# List of lib source files
# ----------------------------------------------------------------------------
LIB_SRCS := calculos.c
LIB_DSP_OBJS := $(LIB_SRCS:%.c=dsp_obj/%.o)
LIB_OBJS := $(LIB_DSP_OBJS:%.o=%.lib)
all: dsp_obj/.created
$(C6RUN_CC) $(C6RUN_CFLAGS) -o $(LIB_DSP_OBJS) $(LIB_SRCS) -DUSE_DSP;
$(C6RUN_AR) $(C6RUN_ARFLAGS) $(LIB_OBJS) $(LIB_DSP_OBJS);
all_host: dsp_obj/.created
gcc -c -o $(LIB_DSP_OBJS) $(LIB_SRCS);
ar rcs $(LIB_OBJS) $(LIB_DSP_OBJS);
dsp_obj/.created:
#mkdir -p dsp_obj
#touch dsp_obj/.created
clean:
rm -rf dsp_obj;
distclean: clean
So the question is: how should I configure my Makefile so it will produce a .a file instead of a .lib?
The line that causes the .lib extension is LIB_OBJS := $(LIB_DSP_OBJS:%.o=%.lib) which replaces .o in each file in LIB_DSP_OBJS with .lib.
Change the .lib to .a in that line and see if that does what you need.

How to build *.so module in Automake and a libtool-using project?

I have the same problem as others have:
I have a *.la file generated by libtool in an Automake project (e.g. module.la),
but I need the *.so of it to use it for dlopen() (eg. module.so).
But: project is configured and built with --disable-shared to make sure the created main binary is one big statically linked program, e.g. main.x (easier for deployment and debugging). Thus *.so files are not created.
The program main.x is a huge framework-like application which is capable of loading extensions (modules) via dlopen() -- despite it being linked statically.
This works fine when I build module.so by hand. But putting this to work in Makefile.am seems impossible to me. Yes, I can write lib_LTLIBRARIES, but with my standard --disable-shared I do not get a *.so file.
lib_LTLIBRARIES = module.la
module_so_SOURCES = module.cpp
The file module.la is created, which dlopen() refuses to load (of course).
I tried to put rules into Makefile.am building it manually and that works:
# Makefile.am (yes, .am)
all: mm_cpp_logger.so
SUFFIXES = .so
%.so: %.cpp
$(CXX) $(CXXFLAGS) -fPIC -fpic -c -I $(top_srcdir)/include -o $# $<
%.so: %.o
$(CXX) $(LDFLAGS) -shared -fPIC -fpic -o $# $<
But this can only be a workaround. I do not get all the nice auto-features like dependency-checking and installation.
How can I build module.so with still building the main program with --disable-shared (or with the same effect) in the Makefile.am-way?
can I postprocess *.la files to *.so files with a special automake rule?
can I tweak the lib_LTLIBRARIES process to create *.so files in any case?
What you are looking for is called a module. You can tell Autotools to create a static binary (executable) by adding -all-static to the LDFLAGS of the application. I think this is the preferred way over using --disable-shared configure flag (which really is aimed at the libraries rather than the executable)
Something like this should do the trick:
AM_CPPFLAGS=-I$(top_srcdir)/include
lib_LTLIBRARIES = module.la
module_la_LDFLAGS = -module -avoid-version -shared
module_la_SOURCES = mm_cpp_logger.cpp
bin_PROGRAMS = application
application_LDFLAGS = -all-static
application_SOURCES = main.cpp
The .so file will (as usual) end up in the .libs/ subdirectory (unless you install it, of course).
And you can build both your application and plugins in one go (even with a single Makefile.am), so there is no need to call configure multiple times.
The use of -fPIC (and friends) should be auto-detected by Autotools.
Update: here's a little trick to make the shared-libraries available where you expect them. Since all shlibs end up in .libs/, it is sometimes nice to have them in a non-hidden directory.
The following makefile snippet creates convenience links (on platforms that support symlinks; otherwise they are copied). Simply adding the snippet to your makefile (i usually use an -include convenience-link.mk) should be enough (you might need an AC_PROG_LN_S in your configure.ac)
.PHONY: convenience-link clean-convenience-link
convenience-link: $(lib_LTLIBRARIES)
#for soname in `echo | $(EGREP) "^dlname=" $^ | $(SED) -e "s|^dlname='\(.*\)'|\1|"`; do \
echo "$$soname: creating convenience link from $(abs_builddir)/.libs to $(top_builddir)"; \
rm -f $(top_builddir)/$$soname ; \
test -e $(abs_builddir)/.libs/$$soname && \
cd $(top_builddir) && \
$(LN_S) $(abs_builddir)/.libs/$$soname $$soname || true;\
done
clean-convenience-link:
#for soname in `echo | $(EGREP) "^dlname=" $(lib_LTLIBRARIES) | $(SED) -e "s|^dlname='\(.*\)'|\1|"`; do \
echo "$$soname: cleaning convenience links"; \
test -L $(top_builddir)/$$soname && rm -f $(top_builddir)/$$soname || true; \
done
all-local:: convenience-link
clean-local:: clean-convenience-link
I've solved a similar problem using the noinst_LTLIBRARIES macro.
The noinst_LTLIBRARIES macro creates static, non installable libraries to be only used internally. all noinst_LTLIBRARIES static libraries are created also if you specify the --disable-static configure option.
lib_LTLIBRARIES = libtokenclient.la
noinst_LTLIBRARIES = libtokenclient_static.la
libtokenclient_la_SOURCES = $(TOKEN_SERVER_CLIENT_SOURCES) cDynlib.c cDynlib.h token_mod.h
libtokenclient_la_CFLAGS = #BASE_CFLAGS#
libtokenclient_la_CXXFLAGS = $(libtokenclient_la_CFLAGS)
libtokenclient_la_LIBADD = #B_BASE_OS_LIBS#
libtokenclient_la_LDFLAGS = #LT_PLUGIN_LIBS_FLAGS# #LIBS_FLAGS# $(TOKEN_SERVER_CLIENT_EXPORT_SYMBOLS)
libtokenclient_static_la_SOURCES = $(libtokenclient_la_SOURCES)
libtokenclient_static_la_CFLAGS = $(libtokenclient_la_CFLAGS)
libtokenclient_static_la_CXXFLAGS = $(libtokenclient_static_la_CFLAGS)
token_test_SOURCES = $(TEST_SOURCES)
token_test_LDADD = #B_BASE_OS_LIBS# libtokenclient_static.la
token_test_CFLAGS = #BASE_CFLAGS#
token_test_CXXFLAGS = $(token_test_CFLAGS)
I use noinst_LTLIBRARIES static libraries for 2 reasons:
to speed up compile time I create static libraries to be used as intermediate containers for code that shall be linked against more than once: the code is compiled just once, otherwise automake would compile same source files once for each target
to statically link the code to some executable
One thing that could work according to the libtool documentation for LT_INIT is to partition your build into two packages: the main application and the plugins. That way you could (in theory) invoke:
./configure --enable-shared=plugins
and things would work the way you would expect.

Cannot compile with makefile - undefined reference to `boost::re_detail

I got an assignment to improve running time of some code. The only problem is, I can't even compile it to run it on my machine in the first place. Every time I try, it stops somewhere in the midst of compiling saying this:
"undefined reference to `boost::re_detail::put_mem_block(void*)'
collect2: ld returned 1 exit status make: * [cpu] Error 1"
This is how makefile looks:
SHELL = /bin/bash
OBJECTS = main.o atom.o molecule.o charges.o pdb.o asa.o amino.o chain.o addition.o string_operation.o pdb_peptide.o protein_chain.o residue_atom.o chain_residue.o residue_contact.o atom_grid.o circles.o atom_space_calculations.o
OBJDIR = obj
VPATH = src:src/ext:$(OBJDIR)
CFLAGS = -O3 -Wall -lm -lboost_regex -L/usr/local/boost/lib
HDIRS = src,src/ext,src/qt_redistributable, usr/lib, usr/local/lib, usr/local/lib/include/boost, /usr/local/lib/lib/
IOPTS = $(addprefix -I, $(HDIRS))
cpu : $(addprefix $(OBJDIR)/, $(OBJECTS) $(CPUOBJS))
g++ $(CFLAGS) -o mcpu $^
$(OBJDIR)/%.o : %.cpp
g++ $(CFLAGS) $(IOPTS) -c $< -o $#
clean :
rm obj/*.o $(PROG)
I'm using Linux Mint x64 and I have tried everything I googled out. Installed the whole boost library in usr/local/lib (for no obvious reason because it didn't help), tried to edit LD PATH (I'm very new to Linux and I have no idea if that went right) and lots of stuff, but this thing doesn't seem to go through. Any help appreciated.
One problem with your makefile happens when you link your program. As you can see in these questions with g++ the order of your arguments at link time is really important. You need to put your libraries after your object files. One easy way to solve would be separating your linker flags (LDFLAGS) from the compiler flags (CFLAGS), and then putting LDFLAGS after $^ (your object files) in the link command.
CFLAGS = -O3 -Wall
LDFLAGS = -L/usr/local/boost/lib -lm -lboost_regex
cpu : $(addprefix $(OBJDIR)/, $(OBJECTS) $(CPUOBJS))
g++ $(CFLAGS) -o mcpu $^ $(LDFLAGS)
$(OBJDIR)/%.o : %.cpp
g++ $(CFLAGS) $(IOPTS) -c $< -o $#
As can be seen in the Catalogue of Built-In Rules:
Linking a single object file
n is made automatically from n.o by running the linker (usually called
ld) via the C compiler. The precise recipe used is:
$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
and Variables Used by Implicit Rules:
LDFLAGS
Extra flags to give to compilers when they are supposed to invoke the linker,
ld, such as -L. Libraries (-lfoo) should be added to the LDLIBS variable
instead.
So in this case -lboost_regex should be set or added to LDLIBS, not LDFLAGS.

Setting Variables within Makefile commands

I'm facing a silly problem with GNU makefile.
I want to define two targets to build a c program; one with debugging and the other without.
runNoDebug: setNoDeb objs runMe
runDebug: setDeb objs runMe
setNoDeb:
{EXPORT} MyDEBUG= -O3
setDeb:
{EXPORT} MyDEBUG="-DDEBUG=1 -g"
objs: cFiles
$(CC) -o $# $^ $(cFiles) $(CFLAGS) $(LIBS) $(MYDEBUG)
runme: objs
./oo
Errors arise on running this makefile, the command to set debugging executes on the subshell causing errors. If "Export" is added, the variable is defined in that subshell.
I want to define this variable in the makefile iteself to be used while building objects.
Is it possible? Or should I duplicate the "objs: cFiles" target?
You need target-specific variable values :
This feature allows you to define different values for the same variable, based on the target that make is currently building.
runNoDebug: setNoDeb runMe
runDebug: setDeb runMe
setNoDeb: CFLAGS += -O3
setNoDeb: objs
setDeb: CPPFLAGS += -DDEBUG=1
setDeb: CFLAGS += -g
setDeb: objs
objs: $(cFiles)
$(CC) $(CFLAGS) $^ $(LIBS) -o $#

Resources