Jam Object rule and directories - jam

I suspect that the manual is actually saying what I'm doing wrong, but I can't really see a solution; the problem occurs when the .c file and the .o file to be build are not in the same directory, and the .c file has an automatic dependency on a .h file which has to be generated on the fly. The problem can be probably be solved by manually setting dependencies between the .c and .h file, but I would like to avoid that.
I have the following directory structure:
weird/
Jamfile
b.c
src/
a.c
c.c
The src/a.c file is like this:
#include "src/a.h"
int main(int argc, char *argv[])
{
return 0;
}
The b.c file is like this:
#include "src/b.h"
int main(int argc, char *argv[])
{
return 0;
}
The src/c.c file is like this:
#include "c.h"
int main(int argc, char *argv[])
{
return 0;
}
The Jamfile is:
rule CreateHeader
{
Clean clean : $(1) ;
}
actions CreateHeader
{
echo "int x = 10;" > $(1)
}
Object a.o : src/a.c ;
Object b.o : b.c ;
Object c.o : src/c.c ;
CreateHeader src/a.h ;
CreateHeader src/b.h ;
CreateHeader src/c.h ;
The following command correctly creates b.o and src/b.h:
jam b.o
The following command creates src/a.h, but then GCC fails to create a.o; the reason is quite obviously that the #include in a.c mentions src/a.h while in fact should simply refer to a.h:
jam a.o
The following command fails completely, and does not even create c.h; the reason is probably that when Jam analyzes c.c it generates a dependency on c.h instead of src/c.h, and in the Jamfile there are no rules for generating c.h:
jam c.o
This command compiles properly if I explicitly ask to generate src/c.h before asking for c.o:
jam src/c.h
jam c.o
In my opinion the jam src/c.h should not be necessary. What's wrong here? Check the Jam manual for more information, particularly under the section Header File Scanning.
Added after I accepted the answer
I kept experimenting a little bit with the constructs suggested by the author of the accepted answer, and I'll post here the results. In this setting you can type:
jam app
And the application will be linked under bin/app. Unfortunately I had to use a UNIX path when setting LOCATE_TARGET, and my understanding is that this is not exactly a good practice.
Directory Structure:
project/
Jamfile
src/
main.c
gen/
bin/
obj/
File Jamfile:
SubDir TOP ;
rule CreateHeader
{
MakeLocate $(1) : $(LOCATE_SOURCE) ;
Clean clean : $(1) ;
}
actions CreateHeader
{
BUILD_DATE=`date`
echo "char build_date[] = \"$BUILD_DATE\";" > $(1)
}
SEARCH_SOURCE = src ;
LOCATE_TARGET = bin/obj ;
SubDirHdrs gen ;
Object main.o : main.c ;
LOCATE_TARGET = bin ;
MainFromObjects app : main.o ;
LOCATE_SOURCE = gen ;
CreateHeader info.h ;
File src/main.c
src/main.c
#include <stdio.h>
#include "info.h"
int main(int argc, char *argv[])
{
printf("Program built with Jam on %s.\n", build_date);
return 0;
}

Changing all #include directives to omit the path (i.e. '#include "a.h' etc.) and changing the Jamfile to the following will solve your issues:
SubDir TOP ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) src ] ;
LOCATE_SOURCE = [ FDirName $(SUBDIR) src ] ;
rule CreateHeader
{
MakeLocate $(1) : $(LOCATE_SOURCE) ;
Clean clean : $(1) ;
}
actions CreateHeader
{
echo "int x = 10;" > $(1)
}
Object a.o : a.c ;
Object b.o : b.c ;
Object c.o : c.c ;
CreateHeader a.h ;
CreateHeader b.h ;
CreateHeader c.h ;
Here're the details:
SubDir should always be invoked in a Jamfile. It sets up several helpful (and in some cases necessary) variables, including SUBDIR, SEARCH_SOURCE, and LOCATE_SOURCE which are used here.
Adding the "src" subdirectory to SEARCH_SOURCE allows you to omit the "src/" part for the source files in the Object rule invocations. SEARCH_SOURCE is also automatically added to the include directories, which is why the #include directories can be shortened.
LOCATE_SOURCE is the directory where generated source files (e.g. generated yacc sources and headers) are placed. For sake of consistency CreateHeader uses this variable. Note that this allows (and requires) you to omit the "src/" part in the CreateHeader invocations.
So the general thrust of these changes is to omit the "src/" part from target names used in the Jamfile. It is generally recommended to omit directory components in Jamfiles (and use grist for disambiguation instead). It is important to note that the way Jam works targets with the names "src/a.h" and "a.h" are different targets, even if the former is considered to be located in "." and the latter in "./src" (e.g. by means of the on-target SEARCH or LOCATE variables). With the files you gave Jam's header scanning results in the following include dependencies (those are target names):
src/a.c : src/a.h
b.c : src/b.h
src/c.c : c.h
This makes obvious why jamming "c.o" fails: The target "c.h" is unknown, since the target name of the header you declare to be generated is "src/c.h". Hence jam ignores the include dependency. The reason for the failing "jam a.o" is the one you suspected.
The change I suggest requires adjusting the #include directives in the source files, which may not be desirable/possible in your actual use case. The situation would still be salvageable. E.g. you can change the Jamfile as suggested, but extend the CreateHeader rule:
rule CreateHeader
{
MakeLocate $(1) : $(LOCATE_SOURCE) ;
Clean clean : $(1) ;
Depends src/$(1) : $(1) ;
NotFile src/$(1) ;
}
This is obviously a bit of a hack. It defines the targets "src/a.h" and friends as pseudo targets, each depending on the corresponding actual target ("a.h" etc.). This way Jam's header scanning will result in a known target regardless of whether it has the "src/" prefix or not.
The less hacky solution is to explicitly declare the include relations, though:
Includes a.c : a.h ;
Includes b.c : b.h ;

Related

Strange behavior with gcc and inline

I want to define an inline function in a header file (.h) which can be included by numerous source files (.c). Here is a minimal example with 1 header and 2 source files:
Header file foo.h
int ifunc(int i);
extern inline
int
ifunc(int i)
{
return i + 1;
}
Source code file: foo.c
#include <stdio.h>
#include "foo.h"
int foo2(int i);
int main()
{
printf("%d\n", foo2(1));
return 0;
}
Source code file foo2.c
#include "foo.h"
int foo2(int i)
{
return ifunc(i);
}
The problem
When I compile with optimization,
gcc -g -Wall -O2 -o foo foo.c foo2.c
$ ./foo
2
everything works fine. However when I turn off optimization, I get this error:
gcc -g -Wall -o foo foo.c foo2.c
/tmp/cc3OrhO9.o: In function `foo2':
foo2.c:5: undefined reference to `ifunc'
Can someone please explain how to fix so that I can run the code with and without -O2? I am using gcc 4.8.5.
if you replace foo.h with
static inline int ifunc(int i)
{
return i + 1;
}
Both will work.
Declaring it extern means it'll be defined somewhere else which in your original example does not happen. And the optimized build doesn't flag as an error because it already optimized it to be inline it but the non-optimized build does not find a definition in any of the .o files (since they were all compiled with ifunc being an extern as defined in foo.h).
Declaring as static inline will ensure that it is local to each file (the downside being that if it does not inline it, you'll end up with each .o that needs it having a local copy, so don't overdo it).

how a macro definition is passed from Makefile to a header file?

I am trying to compile the source code twice with a MACRO defined & undefined. So for default the macro is undefined & i want to define this macro through arguments from Makefile, like
$(MAKE) -c $(present_dir)/new_dir -DONE_MACRO=1
so i am using this ONE_MACRO in file.h.
how this definition is reflected and knows to preprocessor. Here im using cygmake. How to pass an MACRO as argument to compiler with cygmake tool.
file.h:-
#if ONE_MACRO
#define some_targets
#else
#define other_targets
#endif
So how this ONE_MACRO is defined from make file, im trying to pass macro as argument as below
Makefile:-
MY_TARGET:
$(MAKE) -C $(present_dir)/target_dir -D ONE_MACRO=1 $(MAKECMDGOALS)
Here's an example of how to do what I think you want:
define_test.c:
#include <stdio.h>
#ifndef X
#define X 1
#endif
int
main()
{
printf("X = %d\n", X);
}
Makefile:
X = 1
CPPFLAGS += -DX=$(X)
define_test: FORCE
$(CC) $(CPPFLAGS) define_test.c -o $#
FORCE:
Then to pass a different value for macro X:
make X=2
(This assumes you want the value of the macro to be an integer; if you want the value to be a string, you have to get a bit more tricky with quoting properly.)
You can also add the definition directly to the CPPFLAGS, e.g.:
make CPPFLAGS+=-DX=2
For every compiler there is an environmental variable, which passes the areguments to compiler/linker. while dealing with other than GCC we need to find that environmental variables before usage.
like wise in my case RVCT31_CCOPT is the variable which passes the arguments to compiler while building.

Makefile pass define at compile time?

I am trying to pass a "define variable called DEBUG" at compile time for a kernel module.
i.e provide the same functionality as DEBUG does below, but in a Makefile for a kernel module.
gcc -o foo -DDEBUG=1 foo.c
Can anyone give me a hint on how this can be achieved?
The Makefile:
# name of the module to be built
TARGET ?= test_module
# How to pass this during compile time? (-D$(DEBUG) or something similar)
DEBUG ?= 1
#define sources
SRCS := src/hello.c
#extract required object files
OBJ_SRCS := $(SRCS:.c=.o)
#define path to include directory containing header files
INCLUDE_DIRS = -I$(src)/includes
ccflags-y := $(INCLUDE_DIRS)
#define the name of the module and the source files
obj-m += $(TARGET).o
$(TARGET)-y := $(OBJ_SRCS)
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
#echo "insert module:\n\t sudo insmod $(TARGET).ko"
#echo "remove module:\n\t sudo rmmod $(TARGET)"
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
I am using the module from link (with a small change in the init function, see the #if #endif statement)
hello.c:
#include <linux/module.h> // included for all kernel modules
#include <linux/kernel.h> // included for KERN_INFO
#include <linux/init.h> // included for __init and __exit macros
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lakshmanan");
MODULE_DESCRIPTION("A Simple Hello World module");
static int __init hello_init(void)
{
#if (DEBUG == 1)
printk(KERN_INFO "DEBUG = 1\n")
#endif
printk(KERN_INFO "Hello world!\n");
return 0; // Non-zero return means that the module couldn't be loaded.
}
static void __exit hello_cleanup(void)
{
printk(KERN_INFO "Cleaning up module.\n");
}
module_init(hello_init);
module_exit(hello_cleanup);
I would like to see that dmesg poduces the following after
sudo insmod test_module.ko
DEBUG = 1
Hello world!
Solution:
ccflags-y := -DDEBUG=$(DEBUG)
Made the code below execute as intended
#if (DEBUG == 1)
printk(KERN_INFO "DEBUG = 1\n")
#endif
ccflags-y := -DDEBUG=$(DEBUG)
Made the code below execute as intended
#if (DEBUG == 1)
printk(KERN_INFO "DEBUG = 1\n")
#endif

libtool doesn't provide library dependencies to link

I am using libtool 2.2.6b on ubuntu lucid, and libtool 2.4.2 on ubuntu precise. On lucid my project will link properly. On precise it fails to link. Here's example code that demonstrates my problem;
configure.ac
AC_INIT([ltp], [0.0.1], [someone])
AM_INIT_AUTOMAKE
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([.m4])
AC_CONFIG_FILES([Makefile foo/Makefile bar/Makefile wah/Makefile])
AC_PROG_CXX
AC_PROG_LIBTOOL
AM_SANITY_CHECK
AC_LANG_CPLUSPLUS
AC_OUTPUT
Makefile.am
SUBDIRS = foo bar wah
ACLOCAL_AMFLAGS = -I .m4
foo/Foo.h
#ifndef FOO_FOO_H_
#define FOO_FOO_H_
namespace Foo
{
class Foo
{
public:
Foo(long l);
private:
long l;
};
}
#endif
foo/Foo.cpp
#include "foo/Foo.h"
namespace Foo
{
Foo::Foo(long l) : l(l) {}
}
foo/Makefile.am
lib_LTLIBRARIES = libfoo.la
libfoo_la_SOURCES = Foo.cpp
libfoo_la_CPPFLAGS =
libfoo_la_LDFLAGS = -release 0.0.1
libfoo_la_LIBADD =
bar/Bar.h
#ifndef BAR_BAR_H_
#define BAR_BAR_H_
#include "foo/Foo.h"
namespace Bar
{
class Bar
{
public:
Bar(const Foo::Foo & f);
private:
Foo::Foo f;
};
}
#endif
bar/Bar.cpp
#include "bar/Bar.h"
namespace Bar
{
Bar::Bar(const Foo::Foo & f) : f(f) { }
}
bar/Makefile.am
lib_LTLIBRARIES = libbar.la
libbar_la_SOURCES = Bar.cpp
libbar_la_CPPFLAGS =
libbar_la_LDFLAGS = -release 0.0.1
libbar_la_LIBADD = -L../foo -lfoo
wah/main.cpp
#include "bar/Bar.h"
int main(int argc, char * argv[])
{
Bar::Bar( 5 );
return 0;
}
wah/Makefile.am
bin_PROGRAMS = wah
wah_SOURCES = main.cpp
wah_CPPFLAGS =
wah_LDADD = -L../bar -lbar
On Lucid, wah links, on Precise, it fails with:
wah/main.cpp:5 undefined reference to `Foo::Foo::Foo(long)'
I can fix this by adding -L../foo -lfoo to wah_LDADD, but really, isn't libtool supposed to do that for me automagically? The libtool manual section on `Linking executables' seems to indicate that is exactly what it should do.
On any Debian machine I use for development, I have to compile and install Libtool by hand, because the Debian-supplied version is patched and ignores dependencies in a way that break my builds.
If Ubuntu's version is similar, you might want to install Libtool from source too.
I suppose you could say it's more of a difference in philosophy. The point of Debian's change is to encourage users to be explicit about what they depend on, which reduces the amount of unnecessary churn when dependencies deep down the tree get upgraded.
When link_all_deplibs=yes (unmodified libtool), if your program wah depends on bar and bar depends on foo, then it is implied that wah depends foo as well.
When link_all_deplibs=no (Debian's modified libtool), if your program wah depends on bar and bar depends on foo, then it is not implied that wah depends foo as well.
So, taking Debian's perspective, this is false in your program: wah does depend on foo by virtue of this line:
Bar::Bar( 5 );
Here, you are calling the constructor of Foo::Foo implicitly. As far as the C++ compiler is concerned, your program is really more like:
Bar::Bar( Foo::Foo( 5 ) );
Therefore, wah depends on foo not just indirectly, but directly. Hence, from Debian's perspective, you are should explicitly link to foo via -lfoo.
In particular, this is not the same situation as libtool's example for Linking Executables. In that example, main.o does not explicitly depend on libm, thus -lm should, in principle, be unnecessary when linking the main.o (main.c does not call cos directly). Perhaps the reason why libtool links recursively is as a work around for older systems where linkers are unable to handle indirect dependencies?
Works for me on Ubuntu 12.04 (Precise Pangolin) 32-bit, libtool 2.4.2.
I did have to change your Makefiles a bit to make dist (more) correctly:
foo/Makefile.am:
lib_LTLIBRARIES = libfoo.la
libfoo_la_SOURCES = Foo.cpp Foo.h
libfoo_la_CPPFLAGS =
libfoo_la_LDFLAGS = -release 0.0.1
libfoo_la_LIBADD =
bar/Makefile.am:
lib_LTLIBRARIES = libbar.la
libbar_la_SOURCES = Bar.cpp Bar.h
libbar_la_CPPFLAGS =
libbar_la_LDFLAGS = -release 0.0.1
libbar_la_LIBADD = -L../foo -lfoo
wah/Makefile.am
bin_PROGRAMS = wah
wah_SOURCES = main.cpp ../bar/Bar.h
wah_CPPFLAGS =
wah_LDADD = -L../bar -lbar
Here's how it links main.cpp:
make[2]: Entering directory `/xxx/ltp-0.0.1/wah'
g++ -DHAVE_CONFIG_H -I. -I.. -g -O2 -MT wah-main.o -MD -MP -MF .deps/wah-main.Tpo -c -o wah-main.o `test -f 'main.cpp' || echo './'`main.cpp
mv -f .deps/wah-main.Tpo .deps/wah-main.Po
/bin/bash ../libtool --tag=CXX --mode=link g++ -g -O2 -o wah wah-main.o -L../bar -lbar
libtool: link: g++ -g -O2 -o .libs/wah wah-main.o -L../bar /xxx/ltp-0.0.1/bar/.libs/libbar.so -L../foo /xxx/ltp-0.0.1/foo/.libs/libfoo.so
isn't libtool supposed to do that for me automagically?
Yes, it does, at least when the distribution tarball is created on a non-Ubuntu distribution. After I autoreconf on an Ubuntu box, I get the same error you do.
Apparently (according to adl) the Ubuntu distro has a patched version of libtool which sets the libtool script variable:
link_all_deplibs=no
I patched the configure generated libtool script to replace all these instances with:
link_all_deplibs=unknown
and everything linked as expected. I suppose you could do the same in a script that invokes autoreconf. Or install a non-patched version of libtool on the Ubuntu host. Or patch the patched libtool on the Ubuntu host. So there's a few options on how to fix it.

Append to beginning of list

I have a makefile that lists the source files: (shortened to relevant)
SRCFOLDER=src/
SOURCES= main.cpp
OBJECTS=$(SOURCES:.cpp=.o)
and I would like to concate the strings together, but for each one in SOURCES. As you can see above, I do it for OBJECTS, but I want to do it like this: (pseudocode)
foreach(src in SOURCES)
src = concate(SRCFOLDER, src)
so that if SOURCES was main.cpp window.cpp, the result would be src/main.cpp src/window.cpp.
I tried this:
SOURCES=$(SOURCES:*=$(SRCFOLDER)/*)
but I get this error:
makefile:12: *** Recursive variable `SOURCES' references itself (eventually). Stop.
SRCFOLDER := src
SOURCES := main.cpp window.cpp
SOURCES := $(addprefix $(SRCFOLDER)/, $(SOURCES))

Resources