Where is the start point of this makefile - c

The following is a makefile I encountered in Postgres, I don't understand how it works. I saw some simple Makefile examples where they have commands to compile, but this one seems to be different. Could anyone explain how this makefile works? Basically I need to understand this one before I modify it for my purpose.
subdir = src/backend/access/transam
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = clog.o multixact.o \
xlogreader.o xlogutils.o
include $(top_srcdir)/src/backend/common.mk
xlog.o: xlog.c $(top_srcdir)/src/include/catalog/catversion.h
Please let me know if you need more information.
Thanks.

subdir = src/backend/access/transam
top_builddir = ../../../..
Set some variables
include $(top_builddir)/src/Makefile.global
Include a global makefile (presumably uses the two previously set variables in some way).
OBJS = clog.o multixact.o \
xlogreader.o xlogutils.o
Create an OBJS variable for the things to be built in this directory (I assume).
include $(top_srcdir)/src/backend/common.mk
Include another makefile (which presumably uses OBJS and defines rules/flags/etc. for building files).
xlog.o: xlog.c $(top_srcdir)/src/include/catalog/catversion.h
Explicitly handle prerequisites to the xlog.o target file (presumably because putting this in OBJS would do something undesirable).
For more about what subdir or OBJS is used for exactly (or what else you can set in this file) you would need to read and understand src/Makefile.global and src/backend/common.mk.

Related

How to include hundreds of folders in a Makefile?

I'm working on a C++ project at work where we need to develop a small piece for a larger application. We were given headers and static libraries for all of the code that we should need to reference. These are strewn throughout multiple folders and we placed all of that inside a common folder.
When writing our code, we'll need to include the headers and libraries as a part of our compilation process. Is there an elegant solution to doing this in a Makefile, or do I have to explicitly list each include folder with -I , each library folder with -L , and each library with -l?
Or is there an alternative to a Makefile that might make sense for this?
Edit: Here is an example of the folder structure:
common
folder1
subfolder1
include
libs
subfolder2
...
subfolder10
folder2
...
...
folder10
code
makefile
ourStuff
There are multiple levels of folders under common containing headers and libraries. We need to include code from there.
It was also asked why we don't just explicitly list the path in our #include statements. This code will be living in the main application once we're done, and it doesn't exactly follow the folder structure we were given.
Well, given the above structure it's simple enough to generate the things you want. For example if you want to add all -I... flags to CXXFLAGS, you can use:
INCDIRS := $(wildcard ../common/*/*/include)
CXXFLAGS += $(addprefix -I,$(INCDIRS))
Similar for -L flags:
LIBDIRS := $(wildcard ../common/*/*/libs)
LDFLAGS += $(addprefix -L,$(LIBDIRS))
Linking all the libraries is slightly more complicated. Assuming they're all static libraries you can do something like this:
LIBFILES := $(notdir $(wildcard ../common/*/*/libs/lib*.a))
LDLIBS += $(patsubst lib%.a,-l%,$(LIBFILES))
Of course this is assuming you don't have any naming conflicts / all libraries are unique.
Obviously, your question can be formulated like this: "Do I have to write a plethora of include paths or is there some managed/automatic way to do that". The question may pop up in the context of a makefile but this is mainly because make does not try to cloak the complexity of software building from the programmer. Trying to evade to another build system buys you nothing if the components you are using were not fitted into the larger build algorithm by their original programmers. If you receive pre-configured build parts (e.g. in form of a CMake project) then you save a great deal of work, needing only to tie together some abstraction level high up in the hierarchy. The downside of this is that you are locked in this build methodology now, possibly with more ramifications radiating out into parts of your project where they do as much harm as good. You may want to read this thread here: https://softwareengineering.stackexchange.com/questions/407056/the-case-against-path-expressions-in-include-directives
The cheapest way to at least partially achieve what you want to do in GNUmake is to use the function wildcard-rec (see https://github.com/markpiffer/gmtt#call-wildcard-reclist-of-globs) which has a fairly flexible input-output-relation. You can e.g. collect all paths which are of the form project/component_a/**/include/ in a whole subtree, or all header files in such a path with project/component_a/**/include/*.h.
PS: simply include gmtt.mk at the top of your makefiles.

Creating target from searched directories

I want to create separate executables for each directory named "test" in my project. Test directory has structure like this:
test.mk
test (dir)
|__test.mk
|__testRun.c
|__testRun.h
test.mk contains dependencies for specific test, testRun.c is the test itself.
So hierarchy looks like this:
ROOT
|__Makefile
|__Module1 (dir)
|__some files
|__test (dir)
|__Module2 (dir)
|__some files
|__test (dir)
|__Module3 (dir)
|__some files
|__test (dir)
|__outdir (dir)
|__test1 (exec)
|__test2 (exec)
|__test3 (exec)
I want to run single Makefile in root parent directory. I want it to search for all test directories and create test executables in outdirectory. So far I have this:
Makefile
CFLAGS = -I$(DIRTEST) -I$(DIRTEST)/..
OUTDIR= ./outdirectory
DIRTEST = $(shell find -type d -not -path "$(OUTDIR)/*" -name "test" -prune )
I have no idea how to create rule that creates target executable from sources and headers from separate directories. I was looking for solution for similar problem, but no luck so far.
Note: I do not want to use recursive make. test.mk looks for example like this:
SRCTEST = module1/test/testRun.c \
module1/module1.c
CFLAGS += -Imodule1
You can use bash scripts files for building variables, in case if you are avoiding a recursive build.
cat module1/test/test.sh
export SRCTEST="module1/test/testRun.c
module1/module1.c"
export CFLAGS="$CFLAGS -Imodule1"
cat module2/test/test.sh
export SRCTEST="module2/test/testRun.c
module2/module2.c"
export CFLAGS="$CFLAGS -Imodule2"
Then your Makefile could looks like:
test1:
source module1/test/test.sh && gcc -o $# $$CFLAGS $$SRCTEST
test2:
source module2/test/test.sh && gcc -o $# $$CFLAGS $$SRCTEST
Also you can do something with include instruction. Redefinition could be avoided by checking the build target, but this is not a good way.
Your examples are not clear enough for us to answer.
For one thing, tt's not clear how the name of the test executable is related to the name of the module. Is it really the case that the modules end with a number and the generated test program should also end with that same number (Module1 -> test1)? Or is there some other relationship? There doesn't appear to be any variable containing a test name in the test.mk file so how is the test name computed?.
Second, it will make your life very difficult if you redefine the same variables in every test.mk file. There is no "scoping" in make that will allow you to say "this instance of CFLAGS is used only for this included makefile". Each time you include a different test.mk file it will overwrite the previous settings.
It CAN be done: you'll need to use a combination of define variables to hold rule definitions, then eval to evaluate the rules.
Let's suppose that you added a new variable to test.mk which defined the test name, and you qualified your variables with this name as well; then your life is much easier:
Module1/test/test.mk would contain:
TESTNAME = test1
test1_SRCTEST = module1/test/testRun.c \
module1/module1.c
test1_CFLAGS = -Imodule1
Now in your main makefile you would create a variable holding the rule you wanted to define:
define MAKETEST
include $T
$$(OUTDIR)/$$(TESTNAME): $$(OUTDIR)/% : $$($$(TESTNAME)_SRCTEST)
$$(CC) $$(CPPFLAGS) $$(CFLAGS) $$($$*_CFLAGS) -o $$# $$^
endef
$(foreach T,$(DIRTEST),$(eval $(MAKETEST)))
Note, this is untested.

Makefile arguments to C definitions - requires clean

I have a makefile that I use to build an embedded project in C. When I build the project I pass an argument like the following so that a #define is set.
make UID=ID123
In the makefile I have
ifdef UID
CFLAGS+=-DUID=\"$(UID)\"
endif
And in the source code e.g. app.h I have
#ifndef UID
#define UID NOUID
#endif
The problem I am facing is that this works only if I clean the project first. Since the project is quite big, this takes a lot of time between recompilations.
How can this be avoided? Can the make program selectively build the files that are affected? Like when a file gets edited? Does removing the object files that this #define affects help or is a bad idea?
The reason this is necessary is so that programming 100 devices, each will have a unique ID passed to the program at build time.
Thanks.
There are several things you can do, but some of there are pretty involved. It's a question of what your priorities are, and how much arcane Make-craft you want to do.
First you can figure out which object files depend on UID. Having such a list will save you a lot of work; for instance, you can remove only those object files and then rebuild them, instead of removing and rebuilding all object files with clean:
clean_uid_objects:
rm -f $(UID_OBJECTS)
You can maintain this list yourself:
OBJECTS := foo.o bar.o
UID_OBJECTS := baz.o qux.o
or with some cleverness you might have Make construct the list on the fly, but explaining that one would take a while.
You can also have Make keep track of which UID you used, the last time you rebuilt the object files. After all, if you haven't changed it, then you don't have to rebuild anything because of it. One way to do that is to record the last UID in a file called, say, UID_SAVE. Then you can include that file in the makefile, and Make will adjust it (and rebuild the makefile, and rerun itself) when you pass it a new UID:
-include UID_save
ifdef UID
#CFLAGS+=-DUID=\"$(UID)\"
ifneq ($(UID),$(OLDID))
.PHONY: UID_SAVE
endif
endif
UID_save:
#echo OLDID:=$(UID) > $#
Once you have that working, you can make UID_SAVE a prerequisite of the object files that depend on UID, so that no cleaning is necessary at all.
I ended up using
.PHONY: myfile1.c myfile2.c myfile1.h
to force rebuild the files that depend on the argument passed.
My answer is similar to Beta's last answer, but it shows the precise systematic method. What you want, is have UID behave as if it were a file, not a variable, so you could depend targets on it. Here is how to do it, see my answer in this post:
How do I add a debug option to Makefile
You write the function DEPENDABLE_VAR. Then, if you want a variable UID to be "dependable", you simply call that function:
$(eval $(call DEPENDABLE_VAR,UID))
and now you can write things like:
foobar.o: UID

Missing header files for linked ".c" file

I have linked a ".c" file to another one. ld doesn't return any error but the compiler can't find included header files in this ".c" file and returns this error:
../libvmi/driver/xen.c:27:20: fatal error: libvmi.h: No such file or directory
Here is the Makefile of my project:
## Source directory
SUBDIRS =
INCLUDES = -I$(top_srcdir) $(top_srcdir)/libvmi
AM_LDFLAGS = -L$(top_srcdir)/libvmi/.libs/ $(top_srcdir)/libvmi/driver $(top_srcdir)/libvmi/libvmi.h
LDADD = -lvmi -lm $(LIBS) $(top_srcdir)/libvmi/driver/xen.c $(top_srcdir)/libvmi/libvmi.h
bin_PROGRAMS = module-list process-list map-symbol map-addr dump-memory
module_list_SOURCES = module-list.c
process_list_SOURCES = process-list.c
map_symbol_SOURCES = map-symbol.c
map_addr_SOURCES = map-addr.c
dump_memory_SOURCES = dump-memory.c
As you see above I thought I should add "$(top_srcdir)/libvmi" to "INCLUDES"; this is the directory that libvmi.h is located.
The original Makefile is:
## Source directory
SUBDIRS =
INCLUDES = -I$(top_srcdir)
AM_LDFLAGS = -L$(top_srcdir)/libvmi/.libs/
LDADD = -lvmi -lm $(LIBS)
c_sources = process-list.c $(top_srcdir)/libvmi/driver/xen.c
bin_PROGRAMS = module-list process-list map-symbol map-addr dump-memory
module_list_SOURCES = module-list.c
process_list_SOURCES = $(c_sources)
map_symbol_SOURCES = map-symbol.c
map_addr_SOURCES = map-addr.c
dump_memory_SOURCES = dump-memory.c
I have modified it to link "libvmi/driver/xen.c" to process-list.c file which are located in different directories.
This is because of something's wrong in Makefile, yes?
Add a -I to the path you added. Note this is a compiler, not linker question
The reason ld doesn't return an error is because it is not invoked. The error message you are getting is coming from the compiler, and the loader is not invoked until the compiler is successful.
Yes, you do need to add $(source_dir)/libvmi to INCLUDES; you just need to do it symmetrically with the existing entry:
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/libvmi
Note the -I preceding the directory name. You have a similar problem in AM_LDFLAGS and LDADD:
AM_LDFLAGS = -L$(top_srcdir)/libvmi/.libs/ -L$(top_srcdir)/libvmi/driver
LDADD = -lvmi -lm $(LIBS)
but you do not want to add the header file $(top_srcdir)/libvmi/libvmi.h to the load flags. Headers are not libraries; headers are not appropriate for sending to the linker/loader. You should only supply the linker/loader with object files, libraries, and options — no source files, no headers.
That more or less deals with the surface issues. What is the real problem you are trying to solve?
If you need to link with code from a library built in libvmi directory, why don't you make the dependency changes in this makefile to pick up the library from the libvmi directory (and separately run the build for the library in the libvmi directory)? Or, if you really want to do the compilation in the current directory (but why?), create links to the libvmi files locally (or copy them; no, on second thoughts, don't copy them), and compile them locally? Mixed directory working is painful at best — and to be avoided when possible, which it almost always is.
I note that the original makefile does in fact include -lvmi on the link line, so what I outlined is what you're expected to use. Why isn't that working for you? This is very much an XY Problem. I recommend reworking the question so that you get a solution to the real problem you started out with, rather than the artificial problem you ran into attempting to solve the real problem in a misguided way.

How can I define #define in my Make files

In my c/c++ files, there are multiple #define. As an example:
#ifdef LIBVNCSERVER_HAVE_LIBZ
/* some code */
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
/* some more code */
Can you please tell me how can I modify my Makefile.in so that I have those #define in ALL files during compilation?
Thank you.
-DLIBVNCSERVER_HAVE_LIBZ -DLIBVNCSERVER_HAVE_LIBJPEG
You could pass those in CPPFLAGS,
CPPFLAGS = -DLIBVNCSERVER_HAVE_LIBZ -DLIBVNCSERVER_HAVE_LIBJPEG
or make new variable
CUSTOMDEFINES = -DLIBVNCSERVER_HAVE_LIBZ -DLIBVNCSERVER_HAVE_LIBJPEG
and pass it to CPPFLAGS = -DEXISTINGFLAGS $(CUSTOMDEFINES)
Those are finally will pass to gcc/g++ -D...
$(CC) $(CPPFLAGS)
Add the line below, to your makefile:
DEFINES=LIBVNCSERVER_HAVE_LIBZ LIBVNCSERVER_HAVE_LIBJPEG
...
... further on in your makefile on the line where it says ....
...
$(cc) ($(addprefix -D, $(DEFINES))) .....
...
...
This is to serve as an example, you only add another define to the DEFINES variable which gets referenced on the line as shown $(cc) -D$(DEFINES) in which the make will automatically expand the variable and compile those that are #ifdefd.
Thanks to R Samuel Klatchko for pointing out a small amiss...this is specifically for GNU's make, you can use addprefix do properly do that ($(addprefix -D, $(DEFINES))).
Don't modify your Makefile.in. (and consider using Automake and converting your Makefile.in to a much simpler Makefile.am). The whole point of those #defines is to let the configure script define them in config.h, and your source files should #include <config.h>. If you are maintaining the package, you will need to write tests in configure.ac to determine whether or not the system being used has libvncserver installed with jpeg and zlib support. If you modify Makefile.in to always define them, then you are making the assumption that your code is only being built on machines where those features are available. If you make that assumption, you should still add checks to configure.ac to confirm it, and have the configure script fail if the dependencies are not met.

Resources