I've got some makefile generated by conan which is included by my main Makefile. That generated Makefile (conanbuildinfo.mak) contains some variable lets say it is something like this:
CONAN_LIBS = librarya libraryb libraryc
Starting with this in my main makefile:
LIBS=-lsocket
I'd like to achieve following end result:
LIBS=-lsocket -llibrarya -llibraryb -llibraryc
so iterate over $CONAN_LIBS and add each variable with -l prefix to LIBS.
How can I do it? :)
With GNU make you can try 'foreach':
CONAN_LIBS = librarya libraryb libraryc
LIBS = $(foreach entry, $(CONAN_LIBS), -l$(entry))
all:
echo $(LIBS)
make all
-llibrarya -llibraryb -llibraryc
Related
I'm trying to use Make to ... make modular Dockerfiles. Long story short, I want to centralize certain elements and make the composable and reusable, like classes and functions really, but the Dockerfile syntax does not - and according to the developers, will not - offer any facilities in the image of C's #include or similar composability solutions. Not to worry, #include and friends to the rescue!
Except...
I have the following Makefile in my project:
BUILD_DIR := ${CI_PROJECT_DIR}/build
TEMPLATE_FILES := $(shell find ${CI_PROJECT_DIR} -name '*.build')
TEMPLATE_FILENAMES := $(foreach file,$(TEMPLATE_FILES),$(BUILD_DIR)/$(notdir $(file)).built)
BUILT_TEMPLATES := $(TEMPLATE_FILENAMES:.build.built=.built)
DOCKER_FILES := $(shell find ${CI_PROJECT_DIR} -name '*.Dockerfile')
DOCKER_OBJS := $(foreach file,$(DOCKER_FILES),$(BUILD_DIR)/$(notdir $(file)))
all: $(BUILT_TEMPLATES) $(DOCKER_OBJS)
$(BUILD_DIR)/%.built: $(TEMPLATE_FILES) $(BUILD_DIR) # build any templated Dockerfiles
cpp -E -P -o $(BUILD_DIR)/$(notdir $#) -I ${CI_PROJECT_DIR}/modules $<
sed -i 's/__NL__ /\n/g' $(BUILD_DIR)/$(notdir $#)
$(BUILD_DIR)/%.Dockerfile: $(DOCKER_FILES) $(BUILD_DIR)
cp $< $(BUILD_DIR)/$(notdir $(#))
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
.PHONY: clean
clean:
-rm -r $(BUILD_DIR)
The objective is to run the templated Dockerfiles through GCC to compile the #includes in them into proper Docker instructions, and just copy the rest of the files. Sounds simple enough.
Except that it looks like all the target files are "offset" from their sources - like the file names are correct, but the contents are from a file elsewhere in the list, and with no discernible order either.
One thing that I'm fairly sure is wrong - but even more wrong otherwise - is the line
$(BUILD_DIR)/%.built: $(TEMPLATE_FILES) $(BUILD_DIR) # build any templated Dockerfiles
By all manuals and documentation, it ought to be
$(BUILD_DIR)/%.built: %.build $(BUILD_DIR) # build any templated Dockerfiles
but that's even worse, because then Make just says make: *** No rule to make target '/docker/build/runner-dart-2-18-firebase.built', needed by 'all'. Stop.
I'm out of ideas here, along with my limited knowledge of Make. What am I missing to make Make make - sorry - my Dockerfiles?
This line:
$(BUILD_DIR)/%.built: $(TEMPLATE_FILES) $(BUILD_DIR)
Says that if make wants to build a target that matches that pattern, and it can find all the prerequisites, then the pattern rule matches and the recipe can be used. Let's ignore BUILD_DIR (note that it's always a bad idea to list a directory as a prerequisite, but that's not causing this problem). Suppose TEMPLATE_FILES is set to the value ./foo/foo.build ./bar/bar.build. Now the above rule expands to:
./build/%.built: ./foo/foo.build ./foo/bar.build ./build
What is the recipe?
cpp -E -P -o $(BUILD_DIR)/$(notdir $#) -I ${CI_PROJECT_DIR}/modules $<
First it's always wrong to create a file that is not exactly $# so you should use just $# not $(BUILD_DIR)/$(notdir $#). But more importantly, what will $< be set to? It is always set to the first prerequisite, and the first prerequisite is always ./foo/foo.build. So every time you run this recipe, regardless of which .built file you're trying to create, you will always be preprocessing the first .build file.
Your idea that you want this instead:
$(BUILD_DIR)/%.built: %.build $(BUILD_DIR)
is correct, in general. Why do you get the error? Because if you are trying to build the target ./build/foo.built, then the stem (part that matches %) is foo. Then make will look to see if the prerequisite foo.build exists or can be created, because you said the prerequisite is %.build. That file does NOT exist and CANNOT be created (make doesn't know how to create it), because the file is ./foo/foo.build not foo.build which is a totally different file.
You have three options. You can either write separate rules for each source directory:
$(BUILD_DIR)/%.built: foo/%.build
...
$(BUILD_DIR)/%.built: bar/%.build
...
Or, you can change your generated files so they are not all in the same directory but instead keep the source directory structure; you would change this:
TEMPLATE_FILENAMES := $(foreach file,$(TEMPLATE_FILES),$(BUILD_DIR)/$(notdir $(file)).built)
BUILT_TEMPLATES := $(TEMPLATE_FILENAMES:.build.built=.built)
to just this:
BUILT_TEMPLATES := $(patsubst %.build,$(BUILD_DIR)/%.built,$(TEMPLATE_FILES))
then create the output directory as part of the recipe:
#mkdir -p $(#D)
cpp -E -P -o $# -I ${CI_PROJECT_DIR}/modules $<
sed -i 's/__NL__ /\n/g' $#
Or finally, you could use VPATH to tell make what directories to look in to find the *.build files:
VPATH := $(sort $(dir $(TEMPLATE_FILES)))
(note, you should choose only one of these options).
simple code in makefile
define fun
#echo this is function
endef
78 all:
79 $(foreach objdir, $(OBJECTDIRS), $(eval $(call fun)))
the err message is :
Makefile:79:* missing separator. Stop.**
Note: i have checked the $(OBJECTDIRS) is not empty and $(oobjdir) too
if i change the code to flowing lines:
define fun
#echo this is function
endef
all:
$(call fun())
then it's running good
The make eval function evaluates the text you give is as a makefile (expects makefile sytnax).
The text #echo this is a function is NOT a makefile.
In other words, if you create a Makefile and you put into it the text:
#echo this is a function
(by itself, with nothing else) and you run make on that makefile, you'll get this same missing separator error.
is it possible in make to choose where the compiled application are saved?
For Example:
My Makefile is in the root folder.
My Source Code is in /src
the compiled application should be saved in
/dist/release/linux
Thanks :) !
Sure - you can do something like this:
VPATH = /src
OUTPUT_DIR = /dist/release/linux
SRC = foo.c bar.c
EXE = foo
$(OUTPUT_DIR)/$(EXE) : $(SRC)
gcc -Wall $(SRC) -o $#
Note that VPATH is a special variable which tells make which directories to look in for source files, so it will find foo.c and bar.c at /src/foo.c and /src/bar.c.
The executable foo will be built at /dist/release/linux/foo.
I'm currently changing one of my projects to cmake for portably. Within the project directory I have a folder with an external library called "boclib", which is build by a regular makefile. I need to link my executable to "ProjectDir"/boclib/bin/libboc.a . My current attempt looks like this:
FIND_LIBRARY(BOCLIB boc ${PROJECT_BINARY_DIR}/boclib/bin)
Message(${BOCLIB})
TARGET_LINK_LIBRARIES(prod ${BOCLIB})
The Meassage output yields the correct library:
"AbsulutePathToProjectDir"/boclib/bin/libboc.a
Which outputs this, when linking:
g++ -lm -ldl CMakeFiles/prod.dir/src/BocData.cpp.o CMakeFiles/prod.dir/src/delay.cpp.o CMakeFiles/prod.dir/src/leoni.cpp.o CMakeFiles/prod.dir/src/main.cpp.o CMakeFiles/prod.dir/src/scope.cpp.o CMakeFiles/prod.dir/src/SerialCom.cpp.o CMakeFiles/prod.dir/src/tester.cpp.o CMakeFiles/prod.dir/src/Utils.cpp.o -o prod boclib/bin/libboc.a -lboost_program_options -lboost_system -lboost_filesystem -lboost_serialization -lboc
There is no -L option for the boclib.
What am I doing wrong?
Any help will be appreciated.
It seems there's two occurence of "boc" library in the g++ command you pasted, the first: boclib/bin/libboc.a that should comes from your target_link_libraries call and a second one: -lboc that must come from something else in your CMakeLists.txt.
You don't need that second one, if you find why it's added and remove it, it should be ok.
I've been using sbox with a Make-based codebase with no problems. Now
I'm using a scons-based codebase, and am getting some odd problems.
It seems that within scratchbox, scons can't find g++. For example, it
attempts to execute things like:
o hello hello.c
When it should be doing:
g++ -o hello hello.c
So presumably its g++ string variable is empty. g++ is present and in
the PATH - "which g++" produces /scratchbox/compilers/bin/g++.
The same source builds fine outside of scratchbox, so it shouldn't be
a problem with scons or the codebase. There are no special environment
variables set outside of scratchbox when it works.
If I symbolically link /usr/bin/g++ to /scratchbox/compilers/bin/g++,
it gets a bit further (produces the correct-looking g++ commands) but
then upon executing them produces:
sb_gcc_wrapper (g++):
/scratchbox/compilers/arm-linux-cs2007q3-51sb3/bin/sbox-arm-none-linux-gnueabi-g++:
No such file or directory
The file listed is present.
PATH contains /scratchbox/compilers/bin, SBOX_REDIRECT_FROM_DIRS contains /usr/bin and SBOX_REDIRECT_TO_DIRS contains /scratchbox/compilers/bin, so I think it should be able to find it.
Any suggestions would be appreciated!
Thanks,
Ray
Edit: Perhaps related - it also can't find pkg-config unless I prepend the full path within the scons file
scons does not propagate the PATH environment variable, so testing e.g. 'which g++' doesn't help much.
Either set the compilers directly, e.g.
env['CXX'] = '/scratchbox/compilers/bin/g++'
Build your own explicit PATH
path = ['/scratchbox/compilers/bin/','/bin', '/usr/bin', '/sbin','/usr/sbin']
env = Environment(ENV = {'PATH' : path})
Or use the PATH env variable from your shell
import os
env = Environment(ENV = {'PATH' : os.environ['PATH']})