How to make two different source directories in a Makefile output to one bin directory? - erlang

I have the following Makefile to build my erlang project:
.SUFFIXES: .erl .beam .yrl
ERL_SRC := $(wildcard src/*.erl)
ERL_OBJ := $(patsubst src/%.erl,ebin/%.beam,${ERL_SRC})
all: main
main: ${ERL_OBJ}
ebin/%.beam: src/%.erl
erlc +debug_info -W -o ebin $<
clean:
rm -fr ebin/*.beam
I'm trying to update this to also build my eunit tests in the test/eunit folder and have the output go to the same ebin folder as the src like this:
.SUFFIXES: .erl .beam .yrl
ERL_SRC := $(wildcard src/*.erl)
ERL_OBJ := $(patsubst src/%.erl,ebin/%.beam,${ERL_SRC})
EUNIT_SRC := $(wildcard test/eunit/*.erl)
EUNIT_OBJ := $(patsubst test/eunit/%.erl,ebin/%.beam,${EUNIT_SRC})
all: main
main: ${ERL_OBJ}
ebin/%.beam: src/%.erl test/eunit/%.erl
erlc +debug_info -W -o ebin $<
clean:
rm -fr ebin/*.beam
eunit: ${EUNIT_OBJ}
test: main eunit
Making main works fine, but if I try make test it fails with:
make: *** No rule to make target `ebin/data_eunit.beam', needed by `eunit'. Stop.
The test module data_eunit.erl is located in test/eunit. The problem seems to be with the ebin/%.beam target. If I swap src/%.erl with test/eunit/%.erl then I can build the tests but not the src. How can I do a build from two source folders and have the output go to one output folder?

You can use the vpath/VPATH in your Makefile
.SUFFIXES: .erl .beam .yrl
# use vpath to tell make where to search for %.erl files
vpath %.erl src eunit
# or use VPATH to tell make where to search for any prerequisite
# VPATH=src:eunit
ERL_OBJ = $(patsubst src/%.erl,ebin/%.beam, $(wildcard src/*erl))
ERL_OBJ += $(patsubst eunit/%.erl,ebin/%.beam, $(wildcard eunit/*erl))
all: main
main: ${ERL_OBJ}
ebin/%.beam: %.erl
erlc +debug_info -W -o ebin $<
clean:
rm -fr ebin/*.beam

Perhaps you should greatly simplify your build. My erlang build systems just invoke erl -make with an Emakefile that looks like this:
{"src/*", [debug_info, {outdir, "ebin"}, {i, "include"}]}.
You could, of course, have more than one src loc, but just mix the tests and the regular code -- you're already mixing them in ebin. Don't make it harder on yourself than it needs to be.

This wont really answer your question, but I dont like to have the risk of polluting my ebin/ with test-enabled code. So this is how I organize my toplevel Makefile:
all:
(cd src && erl -make)
test:
(cd test && erl -make && \
erl -noinput -eval 'eunit:test({dir, "."}, [verbose]), init:stop()')
Then I put the following into src/Emakefile:
{['*'],
[{outdir,"../ebin"}]}.
And into test/Emakefile I put
{['../src/*'],
[debug_info, {d, 'TEST'}]}.
{['*'],
[debug_info, {d, 'TEST'}]}.
So if I run make all then src/*.erl is compiled into ebin/, but if I run make test I compile src/*.erl and test/*.erl into test/ and run all beam files there with unit tests.
When compiling the tests the TEST macro is enabled so that unit-tests are disabled if surrounded with ifdefs as the eunit guide suggest:
-ifdef(TEST).
test_code_() -> ...
-endif.
Its a setup that I'm quite pleased with.

You should make another target that compiles that tree into ebin, make it depend on the original build target.

This is doing what I want:
.SUFFIXES: .erl .beam .yrl
ERL_SRC := $(wildcard src/*.erl)
ERL_OBJ := $(patsubst src/%.erl,ebin/%.beam,${ERL_SRC})
EUNIT_SRC := $(wildcard test/eunit/*.erl)
EUNIT_OBJ := $(patsubst test/eunit/%.erl,ebin/%.beam,${EUNIT_SRC})
all: main
main: ${ERL_OBJ}
${ERL_OBJ}: ${ERL_SRC}
erlc +debug_info -W -o ebin $<
clean:
rm -fr ebin/*.beam
${EUNIT_OBJ}: ${EUNIT_SRC}
erlc +debug_info -W -o ebin $<
eunit: ${EUNIT_OBJ}
test: main eunit
Any other way I can improve this? Maybe move similar compile lines in ${ERL_OBJ} and ${EUNIT_OBJ} to a variable.

Instead of "ebin/%.beam: src/%.erl test/eunit/%.erl" have you tried just:
%.beam: %.erl

Related

Make offsetting file contents during build

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).

How can I insert tcov to Make File

How can i use tcov on Solaris in make file? My make file makes .o files and then the .so files which is copying to the lib's folder. I work with Oracle BRM
CFLAGS_solaris= -g -xcg92 -xprofile=tcov
C++FLAGS_solaris= -g -library=%none -DPIN_NOT_USING_OSTREAM
CPPFLAGS = -I$(INCDIR) -I$(INCDIR_MDS) -DPCMCPP_CONST_SAFE
LDFLAGS_solaris= -G
SL_EXT_solaris= so
and i tried also:
this makes the .so file;
$(LIBBILL): $(OBJECTS) $(C++_OBJECTS) $(INCFILES) Makefile
$(C++) -o $(LIBBILL) $(LDFLAGS) $(OBJECTS) $(C++_OBJECTS) -lm -lpsiu_for_cm -xprofile=tcov
and this makes the .o files
$(OBJECTS): $(INCFILES) Makefile $(FILES)
$(CC) -c $(CFLAGS) $(CPPFLAGS) $(FILES)
the result of that is the brm can't start.
If someone is looking for an answer I found the solution. You have to use
-xprofile=tcov while compiling .o files and also when you links .so file ;)

compiling with HDF5: unable to link library files (fortran 90)

I am currently try to compile these files using HDF5
I have directly linked and included everything necessary ( I think) but still the compile unable to find the files that is needed
This is my Makefile:
CC = h5cc
FC = h5fc
LD = h5fc
FDEBUG = -std -g -traceback
CFLAGS = -g -O0 -Wall -pedantic
FFLAGS = -g -O0 -Wall -I$(H5DIR)/include -L$(H5DIR)/lib/libhdf5hl_fortran.a
LDFLAGS = -I$(H5DIR)/include -L$(H5DIR)/lib/libhdf5hl_fortran.a
#LDFLAGS = -I$(MKLROOT)/include -L$(MKLROOT) -mkl=sequential
# -opt-block-factor=16 -opt-prefetch=4 \
.SUFFIXES:
.SUFFIXES: .c .f .f90 .F90 .o
OBJS = timing.o \
kinds.o \
rw_matrix.o \
EXE = matmul_omp.exe
all: $(EXE)
$(EXE): $(OBJS) matmul_omp.o
$(LD) $(LDFLAGS) -o $# $^
.f90.o:
-$(RM) -f $*.o $*.mod
$(FC) $(FFLAGS) -c $<
.c.o:
$(CC) $(CFLAGS) -c $<
.PHONEY: clean
clean:
THis is the err:
h5fc -I/curc/tools/x_86_64/rh6/hdf5/1.8.13/szip/2.1/zlib/1.2.8/jpeglib/9a/openmpi/1.8.2/intel/13.0.0/include -L/curc/tools/x_86_64/rh6/hdf5/1.8.13/szip/2.1/zlib/1.2.8/jpeglib/9a/openmpi/1.8.2/intel/13.0.0/lib/libhdf5hl_fortran.a -o matmul_omp.exe timing.o matmul_omp.o
gfortran: /usr/lib64/libhdf5hl_fortran.a: No such file or directory
gfortran: /usr/lib64/libhdf5_hl.a: No such file or directory
gfortran: /usr/lib64/libhdf5_fortran.a: No such file or directory
gfortran: /usr/lib64/libhdf5.a: No such file or directory
As you can see that I directly link libhdf5hl_fortran.a. but i dont know why the error is giving a different directory /usr/lib64/
I think you have a couple of things wrong here.
If you are using h5fc then you shouldn't need to add all the include and lib paths. That is the whole point of the helper applications.
You are adding the paths that have Intel, yet your h5fc has a GNU (gfortran) error.
The gfortran build of HDF5 looks as if it does not have the fortran bindings built.
I would suggest trying the following. Using the full paths (as you have done) but call ifort instead of h5fc:
ifort -I/curc/tools/x_86_64/rh6/hdf5/1.8.13/szip/2.1/zlib/1.2.8/jpeglib/9a/openmpi/1.8.2/intel/13.0.0/include \
-L/curc/tools/x_86_64/rh6/hdf5/1.8.13/szip/2.1/zlib/1.2.8/jpeglib/9a/openmpi/1.8.2/intel/13.0.0/lib/libhdf5hl_fortran.a \
-o matmul_omp.exe timing.o matmul_omp.o

Makefile: Choose the Path for compiling file?

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.

Forcing erl -make to recompile files when macros are changed

I tried to do something similar to How to make two different source directories in a Makefile output to one bin directory?, so I have these files (relative to my project root):
Emakefile:
% EMakefile
% -*- mode: erlang -*-
{["src/*", "src/*/*", "src/*/*/*"],
[{i, "include"}, {outdir, "ebin"}, debug_info]}.
test/Emakefile:
% EMakefile
% -*- mode: erlang -*-
{["../src/*", "../src/*/*", "../src/*/*/*"],
[{i, "../include"}, {outdir, "../ebin"}, debug_info, {d, 'TEST'}]}.
Makefile:
EPATH=-pa ebin
all: before_compile
erl -make
all_test: before_compile
cd test
erl -make
cd ..
before_compile: mk_ebin copy_sqlite create_db copy_config copy_dot_app
test: all_test
erl -noshell $(EPATH) \
-s tests run \
-s init stop
rm -f ct.db
clean:
rm -fv ebin/*
... dependencies of before_compile
The problem is that running make test doesn't recompile any modules which are already compiled with make. It seems erl -make doesn't care that they were compiled without TEST defined, it just checks that the modules themselves are older than beam-files. How do I force it to recompile (and avoid recompilation when it isn't needed)?
UPDATE: Strangely, when running make all_test immediately after make clean, it appears that ./Emakefile is used instead of test/Emakefile: I am getting
Recompile: src/tests
Recompile: src/server_protocol_client
etc. and no tests instead of
Recompile: ../src/tests
Recompile: ../src/server_protocol_client
which I get by doing cd test; erl -make manually. Any idea why? Anyway, I've fixed this problem by removing test/Emakefile and replacing all_test in Makefile:
all_test: before_compile
erl -noshell -eval "make:all([{d, 'TEST'}])." -s init stop
all_test: before_compile
cd test
erl -make
cd ..
This is incorrect. Each line produces its own process. Do such:
all_test: before_compile
cd test; \
erl -make

Resources