I have a master Makefile that calls submakefiles inside directories.
Those submakefiles are generated by autotools starting from Makefile.am and configure.ac files.
The first target of the entire project is a shared library, while the others are executables that link against it (so there is a dependency in the main Makefile).
The problem is that I can only see the compilation output of the shared library, while the other projects are just printing warnings and errors (just stderr text, I believe).
I can't understand what is causing this behaviour since all the projects are called from the very same rule in the master Makefile and all the submakefiles are autogenerated from very seemed configuration files.
The snippet of master Makefile that compiles all the targets looks like this:
SUBDIRS = libMylib app1 app2 app3
$(SUBDIRS):
$(ECHO) "-> Building $#"
$(MAKE) -C $#
$(ECHO) "-> Build of $# finished."
The output of "libMylib" is like:
-> Building libMylib
libtool: compile: ppc-linux-gcc -DHAVE_CONFIG_H -I. -I/opt/ELDK/ppc_8xx/usr/include/ -I/opt/ELDK/ppc_8xx/include/ -Wall -std=gnu99 -O2 -MT libMylibF1.lo -MD -MP -MF .deps/libMylibF1.Tpo -c libMylibF1.c -fPIC -DPIC -o .libs/libMylibF1.o
...
libtool: link: ppc-linux-gcc -shared -fPIC -DPIC .libs/libMylibF1.o .libs/libMylibF2.o .libs/libMylibF3.o -Wl,-rpath -Wl,/opt/ELDK/ppc_8xx/lib -Wl,-rpath -Wl,/opt/ELDK/ppc_8xx/lib -lz -lpthread -O2 -Wl,-soname -Wl,libMylib.so.0 -o .libs/libMylib.so.0.0.0
libtool: link: (cd ".libs" && rm -f "libMylib.so.0" && ln -s "libMylib.so.0.0.0" "libawmg.so.0")
libtool: link: (cd ".libs" && rm -f "libMylib.so" && ln -s "libMylib.so.0.0.0" "libMylib.so")
libtool: link: ( cd ".libs" && rm -f "libMylib.la" && ln -s "../libMylib.la" "libMylib.la" )
-> Build of libAwmg finished.
While the output of any "appN" is:
-> Building app1
app1F1.c: In function `app1F1Func1':
app1F1.c:161: warning: unused variable `varA'
app1F2.c:85: warning: `app1F2FuncX' defined but not used
-> Build of app1 finished.
Could anyone please help me?
EDIT:
I found out that I was able to see the compile stuff in "libMylib" because it is "libtoolized".
If I "libtoolize" another project, I can see the linker part of the output (libtool: link:...).
So, considering that make calls a shell (sh) for each line in the rule, that $(MAKE) equals to just "make" and, by default, make is verbose, why do the submake is not printing its output to stdout?
Which flags may be passed to it so that this happens?
It depends on the Makefiles in the sub directories. If, for example, you have a # in front of the compile commands in the app Makefiles, then they will not output the commands that were being run (also look for $(Q), which is used quite commonly when you want to enable/disable verboseness in makefiles). Alternatively, your make commands in the apps directories may be pushing stdout to some files (which would still allow you to see the warnings).
By the same token your library makefile may be incorrectly redirecting stderr elsewhere, which would explain why you don't see any error outputs on that (or it just doens't have any errors...)
Please post the build rules in the other directories (and all associated variable definitions) if you want more help.
Well, my master makefile includes another file that puts a .SILENT rule in.
I haven't noticed that until today.
Removing this rule makes everithing work as expected.
Oh my...
Related
My main development platform is Gentoo on Linux. However, recently I tried to build my program on the fresh VM install on Debian.
My program contains of main binary and couple of dll/so/dylib libraries. One of the libraries depends on the presence of unixODBC/iODBC.
I was told by unixODBC maintainers to use odbc_config script to identify the build parameters.
When I build on Gentoo - everything works fine. There is no problems.
However, when I build on Debian - the build fails because apparently Debian does not produce odbc_config script and instead in this case rely on pkg-config.
So, I need to add a test in configure.ac to check for odbc_config script presence and pass it along to one of the so files generation (lets call it libodbc_lib project).
Could someone please help me with this?
EDIT:
Is this correct to be put in configure.ac:
AC_CHECK_PROG(ODBC,odbc_config,yes)
if test x"${ODBC}" == x"yes" ; then
ODBC_CFLAGS = `odbc_config --cflags`
ODBC_LIBS = `odbc_config --libs` -lodbcinst
else
ODBC_CFLAGS = `pkg-config odbc --cflags`
ODBC_LIBS = `pkg-config odbc --libs` -lodbcinst
fi
AC_SUBST(ODBC_CFLAGS)
AC_SUBST(ODBC_LIBS)
If it is - how do I use ODBC_FLAGS/ODBC_LIBS in my subproject?
EDIT2:
Based on this answer I used the following code:
In the main configure.ac:
AC_CHECK_PROG(ODBC,odbc_config,yes)
if test x"${ODBC}" == x"yes" ; then
ODBC_CFLAGS = `odbc_config --cflags`
ODBC_LIBS = `odbc_config --libs` -lodbcinst
else
ODBC_CFLAGS = `pkg-config odbc --cflags`
ODBC_LIBS = `pkg-config odbc --libs` -lodbcinst
fi
AC_SUBST(ODBC_CFLAGS)
AC_SUBST(ODBC_LIBS)
In the libodbc_lib/Makefile.am:
libodbc_lib_la_CXXFLAGS = -I../../dbinterface \
-DUNICODE \
-DUNIXODBC \
-I#ODBC_CFLAGS#
libodbc_lib_la_LDFLAGS = -L../dbinterface \
-ldbinterface \
#ODBC_LIB#
I regenerated configure, run it successfully and then tried running make.
I got following error:
CXXLD libodbc_lib.la
/usr/lib/gcc/x86_64-pc-linux-gnu/11.3.0/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find #ODBC_LIB#: No such file or directory
What I did wrong?
EDIT3:
After fixing the missing S, I got following compile commands:
make[2]: Entering directory '/home/igor/dbhandler/Debug/libodbc'
/bin/sh ../libtool --tag=CXX --mode=compile g++ -DHAVE_CONFIG_H -I. -I/home/igor/dbhandler/libodbc -I.. -I../../dbinterface -DUNICODE -DUNIXODBC -I#IODBC_CFLAGS# -g -O0 -MT libodbc_lib_la-database_odbc.lo -MD -MP -MF .deps/libodbc_lib_la-database_odbc.Tpo -c -o libodbc_lib_la-database_odbc.lo `test -f 'database_odbc.cpp' || echo '/home/igor/dbhandler/libodbc/'`database_odbc.cpp
libtool: compile: g++ -DHAVE_CONFIG_H -I. -I/home/igor/dbhandler/libodbc -I.. -I../../dbinterface -DUNICODE -DUNIXODBC -I#IODBC_CFLAGS# -g -O0 -MT libodbc_lib_la-database_odbc.lo -MD -MP -MF .deps/libodbc_lib_la-database_odbc.Tpo -c /home/igor/dbhandler/libodbc/database_odbc.cpp -fPIC -DPIC -o .libs/libodbc_lib_la-database_odbc.o
libtool: compile: g++ -DHAVE_CONFIG_H -I. -I/home/igor/dbhandler/libodbc -I.. -I../../dbinterface -DUNICODE -DUNIXODBC -I#IODBC_CFLAGS# -g -O0 -MT libodbc_lib_la-database_odbc.lo -MD -MP -MF .deps/libodbc_lib_la-database_odbc.Tpo -c /home/igor/dbhandler/libodbc/database_odbc.cpp -o libodbc_lib_la-database_odbc.o >/dev/null 2>&1
mv -f .deps/libodbc_lib_la-database_odbc.Tpo .deps/libodbc_lib_la-database_odbc.Plo
/bin/sh ../libtool --tag=CXX --mode=link g++ -I../../dbinterface -DUNICODE -DUNIXODBC -I#IODBC_CFLAGS# -g -O0 -L../dbinterface -ldbinterface -o libodbc_lib.la -rpath /usr/local/lib libodbc_lib_la-database_odbc.lo
libtool: link: g++ -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-pc-linux-gnu/11.3.0/../../../../lib64/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/11.3.0/crtbeginS.o .libs/libodbc_lib_la-database_odbc.o -L../dbinterface -ldbinterface -L/usr/lib/gcc/x86_64-pc-linux-gnu/11.3.0 -L/usr/lib/gcc/x86_64-pc-linux-gnu/11.3.0/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-pc-linux-gnu/11.3.0/../../../../x86_64-pc-linux-gnu/lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/11.3.0/../../.. -lstdc++ -lm -lc -lgcc_s /usr/lib/gcc/x86_64-pc-linux-gnu/11.3.0/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/11.3.0/../../../../lib64/crtn.o -g -O0 -Wl,-soname -Wl,libodbc_lib.so.0 -o .libs/libodbc_lib.so.0.0.0
libtool: link: (cd ".libs" && rm -f "libodbc_lib.so.0" && ln -s "libodbc_lib.so.0.0.0" "libodbc_lib.so.0")
libtool: link: (cd ".libs" && rm -f "libodbc_lib.so" && ln -s "libodbc_lib.so.0.0.0" "libodbc_lib.so")
libtool: link: ar cru .libs/libodbc_lib.a libodbc_lib_la-database_odbc.o
libtool: link: ranlib .libs/libodbc_lib.a
libtool: link: ( cd ".libs" && rm -f "libodbc_lib.la" && ln -s "../libodbc_lib.la" "libodbc_lib.la" )
make[2]: Leaving directory '/home/igor/dbhandler/Debug/libodbc'
I still the variable name there and not their values.
Is it normal?
As UnixODBC upstream does ship and install *.pc files, I would expect that file to be both present and correct and therefore I would ignore any *-config scripts. The pkg-config system is quite well thought out and works even for quite weird cross compilation environments. The *.pc mechanism works well on Linux, on FreeBSD, on OSX, cross-compiling for Windows on Linux, to name a few.
A well-written _config program written in portable shell could do the same by basically reproducing much of the pkg-config logic in portable shell for each and every _config script, hopefully correctly.
However, odbc_config is not a portable shell script. It is a binary executable, i.e. it will regularly break for cross-compiling, as the system you build on will usually not be able to run programs like odbc_config which are built to run on the system you are building for.
And even if the flags from the *.pc files were unsuitable for a very unusual build environment: Using PKG_CHECK_MODULES defines appropriate _CFLAGS and _LIBS variables for the configure script, so even in a very unusual build environments one can always override whatever the *.pc file might contain by calling configure like
../configure ODBC_CFLAGS='-I/weird/stuff -DWEIRD_STRING="moo"' ODBC_LIBS='-L/very/weird/libxyz -lodbc'
So... using odbc_config has no advantages, upstream already provides a odbc.pc file so it is always present, so why not just always use odbc.pc?
So, in configure.ac (if builds without odbc.pc present should fail, otherwise you will have to do some AC_DEFINE and/or AM_CONDITIONAL to conditionally build with or without ODBC support) do
m4_pattern_forbid([PKG_CHECK_MODULES])dnl
PKG_CHECK_MODULES([ODBC], [odbc])
and in any subdirectory (what you call "subproject") Makefile.am or Makefile-files where you need to link somehting against libodbc, put, depending on whether you are building an executable
bin_PROGRAMS += foobar
[…]
foobar_CPPFLAGS += $(ODBC_CFLAGS)
foobar_LDADD += $(ODBC_LIBS)
or a (libtool) library
lib_LTLIBRARIES += libfoo.la
[…]
libfoo_la_CPPFLAGS += $(ODBC_CFLAGS)
libfoo_la_LIBADD += $(ODBC_LIBS)
That should work for all native and cross-compile builds in properly set up build environments, and people can still override odbc_CFLAGS and odbc_LIBS in case of problems.
Of course, you can always AC_CHECK_PROG or AC_PATH_PROG or AC_CHECK_TOOL or AC_PATH_TOOL together with an AC_ARG_VAR for the odbc_config program and then define and AC_SUBST an _CFLAGS and _LIBS variable set to the output of $ODBC_CONFIG --cflags and $ODBC_CONFIG --libs, respectively, and then then use the _CFLAGS and _LIBS vars in Makefile.am/Makefile-files as above.
However, that is a lot of code to write, and with a lot of special cases to consider, and if you have to ask about how to do this you will probably get a lot more wrong than if you just just use PKG_CHECK_MODULES.
You can always add something later if the PKG_CHECK_MODULES route actually does not work for a use case and which cannot be fixed within the pkg-config framework. Until that time (if it ever happens), I would recommend to just use the simple PKG_CHECK_MODULES method and probably be done.
So, I need to add a test in configure.ac to check for odbc_config script presence and pass it along to one of the so files generation
Autoconf has AC_PATH_PROG() for checking for a program in the executable search path. You would of course use AC_SUBST() to define one or more output variables by which to convey the results to the generated makefiles.
But no, coming back around to my comment on the answer to one of your previous questions, what you ought to do is not have configure forward information about the executable, but rather for it to determine the needed flags itself and forward them, via one or more output variables. If you continue to use odbc_config, at least conditionally, then that means having configure run it and capture the output. You should not inject shell command substitutions into your compilation commands.
And if you substitute a different mechanism, whether conditionally or exclusively, then similarly for that. (That's what your other answer describes with respect to pkg-config.)
Im a Windows dev who has no expirience on building C/C++ programs on Linux, but now I need to. Right way would be to go and learn Make and g++ compiler, but before I commit to that I want to figure out some basic stuff.
So I have .c program which is compiled with this makefile:
CUDA_VER=11.5
ifeq ($(CUDA_VER),)
$(error "CUDA_VER is not set")
endif
APP:= deepstream-test3-app
TARGET_DEVICE = $(shell gcc -dumpmachine | cut -f1 -d -)
NVDS_VERSION:=6.0
LIB_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/lib/
APP_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/bin/
ifeq ($(TARGET_DEVICE),aarch64)
CFLAGS:= -DPLATFORM_TEGRA
endif
SRCS:= $(wildcard *.c)
$(info info is $(SRCS))
INCS:= $(wildcard *.h)
PKGS:= gstreamer-1.0
OBJS:= $(SRCS:.c=.o)
CFLAGS+= -I../../../includes \
-I /usr/local/cuda-$(CUDA_VER)/include
CFLAGS+= $(shell pkg-config --cflags $(PKGS))
LIBS:= $(shell pkg-config --libs $(PKGS))
LIBS+= -L/usr/local/cuda-$(CUDA_VER)/lib64/ -lcudart -lnvdsgst_helper -lm \
-L$(LIB_INSTALL_DIR) -lnvdsgst_meta -lnvds_meta \
-lcuda -Wl,-rpath,$(LIB_INSTALL_DIR)
$(info info is $(CFLAGS))
all: $(APP)
%.o: %.c $(INCS) Makefile
gcc -c -o $# $(CFLAGS) $<
$(APP): $(OBJS) Makefile
gcc -o $(APP) $(OBJS) $(LIBS)
install: $(APP)
cp -rv $(APP) $(APP_INSTALL_DIR)
clean:
rm -rf $(OBJS) $(APP)
First thing I tried is to change this Makefile to compile it as C++ program. I changed .c file into .cpp, in makefile I change gcc to g++ everywhere and .c to .cpp everywhere. It gave me error that it couldnt find "main" entry point.
I gave up on that pretty fast and decided just to use lines output of original makefile, ending up with this:
g++ -c -o deepstream_test3_app.o -I../../../includes -I /usr/local/cuda-11.5/include -pthread -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include ./deepstream_test3_app.cpp
g++ -o deepstream-test3-app deepstream_test3_app.o -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -L/usr/local/cuda-11.5/lib64/ -lcudart -lnvdsgst_helper -lm -L/opt/nvidia/deepstream/deepstream-6.0/lib/ -lnvdsgst_meta -lnvds_meta -lcuda -Wl,-rpath,/opt/nvidia/deepstream/deepstream-6.0/lib/
First question, can I combine this 2 launches of g++ into one?
Second, when I make changes to "./deepstream_test3_app.cpp" they are not noticed by compiler. I added
#include <iostream>
...
std::cout << "hello!" << std::endl;
and they are ignored. Its like g++ gets as input some other copy/older version of the file and I dont understand how to go about it.
Hope for any help, sorry if it's all sounds stupid.
Ignoring for the moment the issues surrounding compiling C code with a C++ compiler,
g++ -c -o deepstream_test3_app.o -I../../../includes -I /usr/local/cuda-11.5/include -pthread -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include ./deepstream_test3_app.cpp
g++ -o deepstream-test3-app deepstream_test3_app.o -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -L/usr/local/cuda-11.5/lib64/ -lcudart -lnvdsgst_helper -lm -L/opt/nvidia/deepstream/deepstream-6.0/lib/ -lnvdsgst_meta -lnvds_meta -lcuda -Wl,-rpath,/opt/nvidia/deepstream/deepstream-6.0/lib/
First question, can I combine this 2 launches of g++ into one?
Yes. It is a common practice in makefiles to separate the compilation and linking steps, but that is not mandatory. When there are multiple sources, the separation makes it possible to limit recompilations to only the source files that have changed, but it doesn't make much difference, makefile or not, when there is only one source file.
The one-command version would be mostly a concatenation of the two commands you gave. One would omit the -c option, which instructs g++ to compile but not link, and one would omit the -o deepstream_test3_app.o, which specifies the name of the object file that we are no longer going to create. One would also omit the appearance of deepstream_test3_app.o drawn from the link (second) command, as we are going straight from source file to program. The rest of the options can be reordered to some extent, but all the -l options need to remain in the same order relative to each other and to any object files among the inputs. Here is how I would write it:
g++ -c -o deepstream_test3_app -I../../../includes -I /usr/local/cuda-11.5/include -pthread -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -Wl,-rpath,/opt/nvidia/deepstream/deepstream-6.0/lib/ ./deepstream_test3_app.cpp -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -L/usr/local/cuda-11.5/lib64/ -lcudart -lnvdsgst_helper -lm -L/opt/nvidia/deepstream/deepstream-6.0/lib/ -lnvdsgst_meta -lnvds_meta -lcuda
Second, when I make changes to "./deepstream_test3_app.cpp" they are not noticed by compiler.
The compiler compiles the source file(s) you tell it to.
Its like g++ gets as input some other copy/older version of the file
It is possible that you are indeed telling it to compile a different version than the one you modified. It is also possible that compilation fails, so you don't get a new executable. And it is possible that when you try to run the result, you are not running the program you think you are running. We don't have enough information to know.
With regard to the last, however, do be aware that on Linux, unlike on Windows, the working directory is not automatically in the executable search path. If you want to run the compiled result from the above command, you would want to specify the path to it, which you could most easily do by prepending ./ to its simple name: ./deepstream-test3-app.
I'm using CentOS 6.5. When I do a make, I typically see the full gcc/g++ commands that the Makefile is executing, like
...
gcc -std=gnu99 -DHAVE_CONFIG_H -I. -I/opt/emacs/emacs-24.3/lib -I../src -I/opt/emacs/emacs-24.3/src -g3 -O2 -MT pthread_sigmask.o -MD -MP -MF .deps/pthread_sigmask.Tpo -c -o pthread_sigmask.o pthread_sigmask.c
...
But in some systems, I only see:
$ make
Building test1.o...
Building test2.o...
...
Is it possible to change the "Building ..." messages back to the full gcc/g++ command output?
The output that you see when you run make with a given makefile
depends on how the makefile is written. You will see the
output that the author of the makefile wants you to see.
If a command in a recipe in the makefile is prefixed with #,
then make will not echo the command. So if my makefile is, e.g.
foobar: foobar.o
gcc -o $# $<
foobar.o: foobar.c
gcc -c -o $# $<
then the output of make will be:
gcc -c -o foobar.o foobar.c
gcc -o foobar foobar.o
But if I change the makefile to:
foobar: foobar.o
#echo "Linking foobar"
#gcc -o $# $<
foobar.o: foobar.c
#echo "Compiling foobar"
#gcc -c -o $# $<
then the output becomes:
Compiling foobar
Linking foobar
So to see the output that you would prefer to see you will have to edit the
makefile, removing the #-prefixes from the commands you expect to see
and deleting entirely the commands that print the "Building..." messages.
At least, this is what you would need to do if the makefiles that bother
you in this way build the target using recipes that directly invoke gcc/g++. It
is possible that they build their targets using recipes that invoke some intermediate
tool that doesn't echo the compiler commands and instead emits the "Building..."
messages. Without seeing the makefile(s) I can't say.
I want to build an app and I have multiple modules stored in multiple directories. I've decided to follow this idea, i.e. to have a makefile in each directory and then to merge it. But - as a beginner programmer - I still do not see how to do that. First of all, how would such "partial" makefiles look like. They cannot have main function as there can be only one per binary, though when I try to compile it gcc complains for the undefined reference to main. Secondly, I have no idea how would putting all those modules together look like.
I would appreciate any help, but please try to keep your answers simple. Makefiles are still a bit of black magic to me.
Before you can do anything with a makefile, you must know how to do it without a makefile.
Since you are using gcc, I will assume that your source code is C++.
You haven't told us what your directory structure looks like, so I'll suppose that you have three source files in two directories: primary/main.cc, other/foo.cc and other/bar.cc. (We can deal with header files like foo.h later.) And you want to build myApp.
STEP 1: Doing It By Hand
To do this in one command, you might use:
gcc -Wall primary/main.cc other/foo.cc other/bar.cc -o myApp
This will compile the three source files and link the binary objects together into the executable myApp.
STEP 2: Doing It In Pieces (Do not attempt this until you can get the previous step to work perfectly.)
Instead of building with one command, you could take an intermediate step, compiling the source files into binary object files:
gcc -Wall -c primary/main.cc -o primary/main.o
gcc -Wall -c other/foo.cc -o other/foo.o
gcc -Wall -c other/bar.cc -o other/bar.o
This will produce alpha/main.o, beta/foo.o and beta/bar.o. The compiler won't complain about foo and bar lacking a main() function, because an object file doesn't need one. Then link the objects together into an executable:
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
STEP 3: Doing It Locally (Do not attempt this until you can get the previous step to work perfectly.)
Just like the previous step, but we act in primary/ and other/:
cd primary
gcc -Wall -c main.cc -o main.o
cd ../other
gcc -Wall -c foo.cc -o foo.o
gcc -Wall -c bar.cc -o bar.o
cd ..
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
STEP 4: Using a Makefile (Do not attempt this until you can get the previous step to work perfectly.)
We could have a makefile perform STEP 1, but that isn't really necessary. Write a makefile in primary (i.e. primary/makefile) like this:
main.o:
gcc -Wall -c main.cc -o main.o
(That whitespace in fromt of gcc... is a TAB.)
Now try this:
cd primary
make
cd ../other
gcc -Wall -c foo.cc -o foo.o
gcc -Wall -c bar.cc -o bar.o
cd ..
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
STEP 5: Using Several Makefiles (Do not attempt this until you can get the previous step to work perfectly.)
Write a other/makefile:
both: foo.o bar.o
foo.o:
gcc -Wall -c foo.cc -o foo.o
bar.o:
gcc -Wall -c bar.cc -o bar.o
and a makefile in the top directory, where you're building myApp:
myApp:
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
Now try this:
cd primary
make
cd ../other
make
cd ..
make
STEP 6: Using One Makefile That Calls Others (Do not attempt this until you can get the previous step to work perfectly.)
Edit the top makefile:
myApp:
cd primary; make
cd other; make
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
Now try:
make
If all of this works, what you have is a crude but effective makefile system. There are many refinements possible, when you're ready to take the training wheels off.
EDIT:
If there are many source files in a subdirectory (e.g. other/) and you don't want to maintain a list in the top makefile by hand, there are several ways to handle it. This is one:
OTHER_SOURCES := $(wildcard other/*.cc)
OTHER_OBJECTS := $(OTHER_SOURCES:.cc=.o)
myApp:
cd primary; make
cd other; make
gcc -Wall primary/main.o $(OTHER_OBJECTS) -o myApp
But you should get these makefiles working and understand them, before you try any more streamlining.
I have the following makefile which is a slight modification on others that I have used in the past. There is an odd issue though with my variable ${CXXOPTS} not being used in the .c.o makefile rule. When I execute the makefile, this is what is executed g++ -c -o SeqPrep2.o SeqPrep2.cpp when I expect this to be executed: g++ -Iseqan-03-02-2012 -c -o SeqPrep2.o SeqPrep2.cpp. (Edit: I solved the problem but see my updated question below about why this makefile worked at all in the first place)
L=-lm -lz
SEQANINC=seqan-03-02-2012
DESTDIR=$(HOME)/
BINDIR=bin
CXXOPTS=-I${SEQANINC}
CXX=g++
A=SeqPrep2
USEROPTS=
O=$(patsubst %.cpp,%.o,$(wildcard *.cpp))
SOURCES=$(wildcard *.cpp)
all: ${A} ${O} ${SOURCES}
install: ${O} ${MYLIBS} ${SOURCES}
${CXX} ${USEROPTS} -o ${DESTDIR}${BINDIR}/${A} ${O} ${L}
${A}: ${O} ${MYLIBS} ${SOURCES}
${CXX} ${USEROPTS} -o ${A} ${O} ${L}
clean::
rm -f ${A} ${O}
.c.o:
${CXX} ${CXXOPTS} ${USEROPTS} -c $< -o $#
check-syntax:
${CXX} ${CXXOPTS} ${USEROPTS} -c -o .nul -S ${CHK_SOURCES}
UPDATE:
I changed .c.o to .cpp.o. Is this a case of gnu make guessing that when I asked for a .o file in one of my rules, that it should make it just by running g++ -c -o SeqPrep2.o SeqPrep2.cpp even though I didn't tell it to do that? I guess that is my new question, why did the above makefile work at all, and why did it have the odd behavior I observed. One thing to note is that even though it didn't come though in the formatting, there is a lot of white space between the g++ and the -c, kind of like it was trying to put in my variables, but it didn't. That is partially what originally lead me to believe that it was seeing my rule at all, even though it seems like it didn't now. Thanks for helping me understand how this stuff works.
You've got the rule .c.o but you're compiling cpp files, when I use .cpp.o: it works great! With files: me.cpp us.cpp you.cpp
I get:
Building file me.cpp
g++ -Iseqan-03-02-2012 -c me.cpp -o me.o
Building file us.cpp
g++ -Iseqan-03-02-2012 -c us.cpp -o us.o
Building file you.cpp
g++ -Iseqan-03-02-2012 -c you.cpp -o you.o
g++ -o SeqPrep2 me.o us.o you.o -lm -lz