Typical makefile.am, which works, would look like this for my project:
noinst_LTLIBRARIES = libwinsane.la
CLEANFILES = init.cpp
libwinsane_la_CXXFLAGS = \
-I$(top_srcdir)
libwinsane_la_SOURCES = \
init.cpp
noinst_HEADERS = \
init.h
the issue is that I need to also process resource files. I need to use something like this:
noinst_LTLIBRARIES = libwinsane.la
libwinsane.o: init.o manifest.o
ld -relocatable -o $# init.o manifest.o
manifest.o: manifest.rc utf8.xml
windres -o $# manifest.rc
clean:
rm -f init.o manifest.o libwinsane.o
While this last example is valid makefile by itself (except noinst_LIBRARIES), its obviously wrong syntax for automake. But maybe there is a way for automake to just accept it and produce library in the end somehow?
Off the top of my head, and without 100% verifying its consistency with https://www.gnu.org/software/automake/manual/html_node/Program-and-Library-Variables.html or testing it, something like this should work more or less:
CLEANFILES =
noinst_LTLIBRARIES = libwinsane.la
libwinsane_la_SOURCES =
libwinsane_la_SOURCES += init.cpp
libwinsane_la_SOURCES += init.h
libwinsane_la_CXXFLAGS = -I$(top_srcdir)
libwinsane_la_DEPENDENCIES = manifest.$(OBJEXT)
libwinsane_la_LIBADD = manifest.$(OBJEXT)
CLEANFILES += manifest.$(OBJEXT)
manifest.$(OBJEXT): manifest.rc utf8.xml
windres -o $# $(srcdir)/manifest.rc
A few additional remarks:
The windres recipe probably does not work for out of source builds if utf8.xml has not just been buitl in $(builddir) and is therefore located in $(srcdir). Adding something like -I $(srcdir) to the windres command line will probably fix this, but cannot verify that without a MWE.
You will want to make windres configurable and replace the hard coded windres call by $(WINDRES), made user configurable by AC_ARG_VAR and (if $WINDRES has not been set) AC_CHECK_TOOL, and probably protected with a check in configure.ac that $WINDRES actually works. Depending on your project you can then either AC_MSG_ERROR(...) in case $WINDRES does not work, or AM_CONDITIONAL([HAVE_WINDRES], ...) and then put the Makefile.am parts related to manifest.$(OBJEXT) inside a if HAVE_WINDRES / endif conditional. The actual windres command might be called something like x86_64-w64-mingw32-windres when cross-compiling.
Why do you have CLEANFILES += init.cpp? I have left that out, as you do not want make clean to delete your source files. Or does init.cpp belong to BUILT_SOURCES?
Update: Apparently, I have overlooked something for compiling and linking with libtool: cannot build libtool library from non-libtool objects - any workaround?
Related
I'm often creating png files out of dot (graphviz format) files. The command to do so is the following:
$ dot my_graph.dot -o my_graph.png -Tpng
However, I would like to be able to have a shorter command format like $ make my_graph.dot to automatically generate my png file.
For the moment, I'm using a Makefile in which I've defined the following rule, but the recipe is only available in the directory containing the Makefile
%.eps: %.dot
dot $< -o $# -Teps
Is it possible to define custom implicit GNU Make recipes ? Which would allow the above recipe to be available system-wide
If not, what solution do you use to solve those kind of problem ?
Setup:
Fedora Linux with ZSH/Bash
You could define shell functions in your shell's startup files, e.g.
dotpng()
{
echo dot ${1%.dot}.dot -o ${1%.dot}.png -Tpng;
}
This function can be called like
dotpng my_graph.dot
or
dotpng my_graph
The code ${1%.dot}.dot strips .dot from the file name if present and appends it (again) to allow both my_graph.dot and my_graph as function argument.
Is it possible to define custom implicit GNU Make recipes ?
Not without modifying the source code of GNU Make.
If not, what solution do you use to solve those kind of problem ?
I wouldn't be a fan o modyfying the system globally, but you could do:
Create a file /usr/local/lib/make/myimplicitrules.make with the content
%.eps: %.dot
dot $< -o $# -Teps
Use include /usr/local/lib/make/myimplicitrules.make in your Makefile.
I would rather use a git submodule or similar to share common configuration between projects, rather than depending on global configuration. Depending on global environment will make your program hard to test and non-portable.
I would rather go with a shell function, something along:
mymake() {
make -f <(cat <<'EOF'
%.eps: %.dot
dot $< -o $# -Teps
EOF
) "$#"
}
mymake my_graph.dot
GNU Make lets you specify extra makefiles to read using the MAKEFILES
environment variable. Quoting from info '(make)MAKEFILES Variable':
the default goal is never taken from one of these makefiles (or any
makefile included by them) and it is not an error if the files listed
in 'MAKEFILES' are not found
if you are running 'make' without a specific makefile, a makefile
in 'MAKEFILES' can do useful things to help the built-in implicit
rules work better
As an example, with no makefile in the current directory and the
following .mk files in make's include path (e.g. via
MAKEFLAGS=--include-dir="$HOME"/.local/lib/make/) you can create
subdir gen/ and convert my_graph.dot or dot/my_graph.dot by
running:
MAKEFILES=dot.mk make gen/my_graph.png
To further save some typing it's tempting to add MAKEFILES=dot.mk
to a session environment but defining MAKEFILES in startup files
can make things completely nontransparent. For that reason I prefer
seeing MAKEFILES=… on the command line.
File: dot.mk
include common.mk
genDir ?= gen/
dotDir ?= dot/
dotFlags ?= $(if $(DEBUG),-v)
Tvariant ?= :cairo:cairo
vpath %.dot $(dotDir)
$(genDir)%.png $(genDir)%.svg $(genDir)%.eps : %.dot | $(genDir).
dot $(dotFlags) $< -o $# -T'$(patsubst .%,%,$(suffix $#))$(Tvariant)'
The included common.mk is where you'd store general definitions to
manage directory creation, diagnostics etc., e.g.
.PRECIOUS: %/. ## preempt 'unlink: ...: Is a directory'
%/. : ; $(if $(wildcard $#),,mkdir -p -- $(#D))
References:
?= = := … - info '(make)Reading Makefiles'
vpath - info '(make)Selective Search'
order-only prerequisites (e.g. | $(genDir).) - info '(make)Prerequisite Types'
.PRECIOUS - info '(make)Chained Rules'
within linux kernel source repo, there is Makefile.build under /scripts, which is called many times when building src. there is some target : prerequisite like this:
$(obj)/%.i: $(src)/%.c FORCE
$(call if_changed_dep,cpp_i_c)
and if_changed_dep is
if_changed_dep = $(if $(newer-prereqs)$(cmd-check),$(cmd_and_fixdep),#:)
newer-prereqs is quite straightforward but cmd-check is a bit obsecure.
cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$#))), \
$(subst $(space),$(space_escape),$(strip $(cmd_$1))))
I know that $(cmd_$1) will be expanded to cmd_cpp_i_c, which is the current compiling command
and $(cmd_$#) will be expanded to $(cmd_$(obj)/%.i). for instance if it compiles i2c-core-base.c, it will be $(cmd_i2c-core-base.i) (I omit $(obj))
https://flylib.com/books/en/2.860.1.84/1/ says it is the previous command when compiling.
my question is where I am able to find the evidence since I could not find where cmd_$# is defined.
Thanks a lot for any comments.
After executing the command, the macro cmd_and_savecmd, records the command line into the file ..cmd.
In /scripts/Kbuild.include
cmd_and_savecmd = \
$(cmd); \
printf '%s\n' 'cmd_$# := $(make-cmd)' > $(dot-target).cmd
As make is invoked again during a rebuild, it will include those .*.cmd files.
In /Makefile
-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
So, cmd_$# is used to keep tracks of what command has already been done last time when building a file.
I have a makefile in a directory of mine which builds scripts with certain environment variables set. What if I want to create another makefile in the same directory with different environment variables set? How should I name the two make files? Does makefile.1 and makefile.2 work? How do I call them?
You can give sensible names to the files like makefile.win and makefile.nix and use them:
make -f makefile.win
make -f makefile.nix
or have a Makefile that contains:
win:
make -f makefile.win
nix:
make -f makefile.nix
and use make win or make nix
You can name makefile whatever you want. I usually name it like somename.mk. To use it later you need to tell make what makefile you want. Use -f option for this:
make -f somename.mk
Actually you can have two set of environment variables in the same make file. for example
COMPILER = gcc
CCFLAGS1 = -g
CCFLAGS2 = -Wall
a: main.c
${COMPILER} ${CCFLAGS1} main.c
b: test.c
${COMPILER} ${CCFLAGS2} test.c
then you can just say make a or make b. Depending on what you want.
Also it is possible with -f flag to call which makefile you want to call.
You can do something like this rather than using multiple makefiles for the same purpose. You can pass the environment or set a flag to the same makefile. For eg:
ifeq ($(ENV),ENV1)
ENV_VAR = THIS
else
ENV_VAR = THAT
endif
default : test
.PHONY : test
test:
#echo $(ENV_VAR)
Then you can simply run the make command with arguments
make ENV=ENV1
I have two makefiles in the same directory. Many of the recipes have identical names and here are two solutions:
1. Prefix in make
proja_hello:
#echo "hello A"
projb_hello:
#echo "hello N"
2. Keep two separate files
Project A has makefile. Type make hello.
Project B has a separate make file called projb.mk. Type bmake hello.
This works since I've added alias bmake ='make -f projb.mk to my .bashrc. Note! This command can be called anywhere but only works where projb.mk exists.
Note! You lose autocompletion of make with the alias and typing make -f projb.mk hello is not better than typing make projb_hello.
I am trying to learn how to read makefiles and came across this one. My question is referring to the rule with target %.c. On the first command. where it says
%.c: %.psvn psvn2c_core.c psvn2c_state_map.c psvn2c_abstraction.c
../psvn2c $(PSVNOPT) --name=$(*F) < $< > $#
What does $(*F) < $ < > $# mean? I have posted the whole makefile below.
CC = gcc
CXX = g++
OPT = -g -Wall -O3 -Wno-unused-function -Wno-unused-variable -std=c++11
PSVNOPT = --no_state_map --no_backwards_moves --history_len=0 --abstraction --state_map
psvn2c_core.c:
cp ../psvn2c_core.c ./psvn2c_core.c
psvn2c_state_map.c:
cp ../psvn2c_state_map.c ./psvn2c_state_map.c
psvn2c_abstraction.c:
cp ../psvn2c_abstraction.c ./psvn2c_abstraction.c
%.c: %.psvn psvn2c_core.c psvn2c_state_map.c psvn2c_abstraction.c
../psvn2c $(PSVNOPT) --name=$(*F) < $< > $#
rm -f ./psvn2c_core.c ./psvn2c_state_map.c ./psvn2c_abstraction.c
I want to understand this as a first step towards learning how to run a c++ debugger such as gdb with eclipes or visual studio.
Anything that begins with a $ in a makefile is a variable reference (or, in GNU make, a built-in function), unless it's escaped with another $ (i.e., is $$). The name of the variable can either be a single character, like $#, $A, etc., or it can be one or more characters enclosed in parentheses or braces, like $(#), ${A} (the same as the last ones), $(FOO), ${FOO}, etc.
The GNU make manual has lots of information about all the pre-defined and special variables. These odd-looking variables in particular are automatic variables.
If it's not a variable, and it's part of a recipe, then it's sent to the shell, so you should look at the shell documentation to understand it.
Is it correct to say that < means pipe the input in from and then $< is the first file in the list of dependancies. and > means pipe output to and $# is the output file ie. the file on the left hand side of the : symbol?
Code snippets of makefile:
ERROR_PARSER_YACC = $(SRCDIR)/ermparseyac.y
ERROR_PARSER_LEX = $(SRCDIR)/ermparselex.l
ERM_OBJS = \
$(OBJDIR)/ermparseyac.o \
$(OBJDIR)/ermparselex.o \
$(OBJDIR)/ermclient.o \
$(OBJDIR)/ermcommit.o \
$(OBJDIR)/erminit.o \
$(OBJDIR)/ermlog.o \
$(OBJDIR)/ermmcp.o \
$(OBJDIR)/ermsyslog.o \
$(OBJDIR)/ermparse.o \
$(OBJDIR)/ermreport.o
$(ERM_OBJS): $(SRCDIR)/$(#F:.o=.c)
#echo .... Compiling $(#:.o=.c)
$(IDA_CC) $(SRCDIR)/$(#F:.o=.c) -o $#
The value of SRCDIR is "/home/wholesale/children/dev5/comps/erm/src".
When I run the makefile, I get the following error:
.... Compiling /home/wholesale/children/dev5/comps/erm/obj/ermparselex.c
cc -g -DANSI -DORA817 -DTRACE_ON -DIDA_VERSION='"ISP-RG-V5.10.7GEN2A"' -DNO_MCP -DBUILDING_ERP -I/home/wholesale/children/dev5/comps/erm/include -I/home/wholesale/children/dev5/comps/erm/src -I/home/wholesale/children/dev5/comps/erm/module_test -I/home/wholesale/children/dev5/comps/erm/include -I/home/wholesale/children/dev5/comps/cfm/include -c /home/wholesale/children/dev5/comps/erm/src/ermparselex.c -o /home/wholesale/children/dev5/comps/erm/obj/ermparselex.o
/pf24/wholesale/dvp/comps/erm/src/ermparselex.l:282: error: static declaration of âget_comment_lineâ follows non-static declaration
/pf24/wholesale/dvp/comps/erm/src/ermparselex.l:168: error: previous implicit declaration of âget_comment_lineâ was here
I don't understand how makefile is replacing the location "/home/wholesale/children/dev5/comps/erm/src" to a different location "/pf24/wholesale/dvp/comps/erm/src/" which is not present in the sever.
You seem to be confusing make output with your compiler output. The error messages you showed are not produced by make, but by whatever compiler (probably gcc) you're using.
Note that the assignemt to ERROR_PARSER_LEX is a deffered assignment. The value of SRCDIR is expanded whenever ERROR_PARSER_LEX is used. That might explain why the value of SRCDIR doesn't appear to be what you think it should be.
Edit
The problem doesn't appear to be related to your makefile. Make clearly shows that it's passed /home/wholesale/children/dev5/comps/erm/src/ermparselex.c to the compiler as source file.
The error message which points to a different file probably means that some source file is including something from /pf24.
The -E option of gcc can be quite useful in diagnosing such issues. Replace the -o ... options by it, and it'll output the preprocessed source code to stdout. This should show you which file is including the file in /pf24.