makefile for mix of C and C++ modules

I am trying to come up with a makefile where the target is linked with object files produced by C and C++ sources.

My setup is Ubuntu/gcc:
$ uname -a
Linux srvr1 2.6.24-24-server #1 SMP Fri Sep 18 17:24:10 UTC 2009 i686 GNU/Linux

gcc version 4.2.4

$ cat main.cpp

#include <iostream>
using namespace std;
extern "C" int  clnt(int);
int main(int argc, char *argv[])
{
  int   x = argv[1] ? atoi(argv[1]) : 100;
  int   y = 0;
        y = clnt(x);
        cout << y;
        return 0;
}

$ cat client.c

int clnt(int x)
{
  int   y = 0;
        y = (x < 0) ? x * x : x + x;
        return(y);
}

$ cat makefile

CFLAGS          = -g
CPPFLAGS        = -Wall -ansi -g
OBJS            = main.o client.o
tester: $(OBJS)
        $(CC) -o $@ $(OBJS)

$ make

g++  -Wall -ansi -g  -c -o main.o main.cpp
cc -g -Wall -ansi -g  -c -o client.o client.c
cc -o tester main.o client.o
main.o: In function `std::__verify_grouping(char const*, unsigned int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/usr/include/c++/4.2/bits/locale_facets.tcc:2562: undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::size() const'
/usr/include/c++/4.2/bits/locale_facets.tcc:2571: undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator[](unsigned int) const'
/usr/include/c++/4.2/bits/locale_facets.tcc:2573: undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator[](unsigned int) const'
/usr/include/c++/4.2/bits/locale_facets.tcc:2578: undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator[](unsigned int) const'
main.o: In function `__static_initialization_and_destruction_0':
/usr/include/c++/4.2/iostream:77: undefined reference to `std::ios_base::Init::Init()'
main.o: In function `__tcf_0':
/usr/include/c++/4.2/iostream:77: undefined reference to `std::ios_base::Init::~Init()'
main.o: In function `main':
/home/mgurfink/mydev/amq/cms/main.cpp:12: undefined reference to `std::cout'
/home/mgurfink/mydev/amq/cms/main.cpp:12: undefined reference to `std::basic_ostream<char, std::char_traits<char> >::operator<<(int)'
main.o:(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
make: *** [tester] Error 1

Question #1: why CPPFLAGS are used for the compilation of client.c - even though it correctly uses 'cc', not 'g++' for C file?
Question #2: why it failed to use C++ related stuff when linking?

I do have a working makefile, where I explicitly say to use g++ and it works, see below:

CC = g++
CFLAGS          = -g
CPPFLAGS        = -Wall -ansi -g
OBJS            = main.o client.o
tester: $(OBJS)
        $(CC) -o $@ $(OBJS)
main.o: main.cpp
        $(CC) -c $<
client.o: client.c
        gcc -c $<

But I'd like to keep it simple, as the actual build has many more different modules and I'd hate to have to write a target for every single one of them.

One more piece of info - actual CPPFLAGS need to be different from CPFLAGS, as some that I need are not supported by C compiler, such as -Wno-non-virtual-dtor
Any suggestions?

You shouldn't need any rules to make .o files -- leave them out. make will know to build something.o from something.c or something.cpp as long as something else needs something.o make will also use CFLAGS for .c and CXXFLAGS for .cpp by default.

For the rule building tester, use $(CXX), not $(CC). If you have even one C++ object among there it needs C++ linking.

The $(CXX) did the trick, thanks! Linker is happy.
One remaining issue is that CPPFLAGS are being applied to the plain C compilation, see below:
$ make

g++  -Wall -ansi -g  -c -o main.o main.cpp
cc -g -Wall -ansi -g  -c -o client.o client.c
g++ -o tester main.o client.o

I'd like to see client.c compiled as follows:

 
cc -g -c client.o client.c

as my CFLAGS is set to -g only.

Is it possible to hint make to use CPPFLAGS for C++ and CFLAGS for C files?

I don't know why it's doing that and can't see your computer from here :wink: Post what your Makefile looks like now please.

Sorry, I forgot to show my current make file

CFLAGS          = -g
CPPFLAGS        = -Wall -ansi -g
OBJ1            = main.o client.o
tester: $(OBJ1) 
        $(CXX) -o $@ $(OBJ1)

$ ls *.c *.cpp

client.c  main.cpp

$ make

g++  -Wall -ansi -g  -c -o main.o main.cpp
cc -g -Wall -ansi -g  -c -o client.o client.c
g++ -o tester main.o client.o

Try CXXFLAGS instead of CPPFLAGS.

CXX      = g++
CXXFLAGS = -Wall -ansi -g
CC       = gcc
CCFLAGS  = -g
OBJS     = main.o client.o

tester : $(OBJS)
        $(CXX) -o $@ $(OBJS)

%.o : %.cpp
        $(CXX) -c $(CXXFLAGS) $<

%.o : %.c
        $(CC) -c $(CCFLAGS) $<
2 Likes