[CMake] Dependency tracking with constructed source headers...

Dan Katz dkatz at profitlogic.com
Thu Oct 7 19:22:50 EDT 2004


Hi -

While trying to use CMake for a new C++ system, I ran into the
following issue:




I have a header file which is being generated automatically from some
other source, and I can't figure out how to get it to be built
correctly by CMAKE.  I've boiled the issue down to a simple example.
Assume we have a single "project file" (foo.cpp) like so:

----------------- foo.cpp ------------------------------------
#include "bar.h"
#include <iostream>

using namespace std;

int
main()
{
    cout << bar() << endl;

    return 0;
}
---------------------------------------------------------------




The function "bar()" is in a dynamically generated header file "bar.h"
which is created from "bar.junk" In my sample, that creation happens
by renaming "bar.junk"; in the real system there's a bunch of m4 macro
hell involved.  In any event, the trivial sample looks like this:

---------------- bar.junk --------------------------------------
#include <string>

using std::string;

string
bar()
{
    return "fubar!!";
}
------------------------------------------------------------------




I then have a CMakeLists.txt which I think should build the system:

---------------- CMakeLists.txt ----------------------------------
PROJECT (foo)

# bar.h will be generated here...
INCLUDE_DIRECTORIES(${foo_BINARY_DIR})

# how to build bar.h
ADD_CUSTOM_COMMAND(
  OUTPUT           ${foo_BINARY_DIR}/bar.h
  COMMAND          cp
  ARGS             ${foo_SOURCE_DIR}/bar.junk ${foo_BINARY_DIR}/bar.h
  MAIN_DEPENDENCY  ${foo_SOURCE_DIR}/bar.junk)


ADD_EXECUTABLE(foo foo.cpp ${foo_SOURCE_DIR}/bar.junk)
-------------------------------------------------------------------




I now try to build the system and get the following session
transcript:

-----------------------building foo -------------------------------
$ pwd
/home/dkatz/foo_build

$ cmake ../foo   # ../foo is where foo.cpp, bar.junk, and 
                 # CMakeLists.txt all live
-- Check for working C compiler: gcc
-- Check for working C compiler: gcc -- works
-- Check for working CXX compiler: c++
-- Check for working CXX compiler: c++ -- works
-- Configuring done
-- Generating done
-- Build files have been written to: /home/dkatz/foo_build

$ make
Building dependencies. cmake.depends...
cmake.depends is up-to-date
Building object file foo.o...
/home/dkatz/foo/foo.cpp:1:17: bar.h: No such file or directory/home/dkatz/foo/foo.cpp: In function `int main()':
/home/dkatz/foo/foo.cpp:10: error: `bar' undeclared (first
   use this function)
/home/dkatz/foo/foo.cpp:10: error: (Each undeclared
   identifier is reported only once for each function it appears in.)
make[1]: *** [foo.o] Error 1
make: *** [default_target] Error 2
--------------------------------------------------------------------




After taking a look at the generated Makefile, I noticed that the
build target for bar.h was built correctly (i.e., worked if called by
hand via "make /path/to/build/bar.h", but that bar.h was never
constructed because it was not listed as a dependency for foo.o:

--------------------- foo.o target ---------------------------------
foo.o: /home/dkatz/foo/foo.cpp
	@echo "Building object file foo.o..."
	c++ -o foo.o     $(INCLUDE_FLAGS)  -c /home/dkatz/foo/foo.cpp
--------------------------------------------------------------------




So I guess the question is:  why didn't the system pick up that foo.o
depends on bar.h?  And how can I make it do so?  I played around with
ADD_DEPENDENCIES a little bit, but couldn't figure out how to make it
work.  Any help would be appreciated.

Dan



P.S.  I did take a look at FAQ 2.4, and in fact I patterned my
CMakeLists.txt off of the snippets shown there.  But with only a
generated header, I can't seem to get it to work...




More information about the CMake mailing list