Suppose I have a library that I would like to use make to install:
// library = foo
$ ls foo/
lib include
$ ls foo/lib
foo.h
$ ls foo/include
foo-1.2.a foo-1.2.o foo-1.2.etc
// makefile
.PHONY: install-foo
foo=/path/to/unzipped/foo
current_dir=$(shell pwd)
install-foo:
- cd $(foo); ./configure --prefix=$(current_dir); make; make install
The above will always install
//makefile 2
.PHONY: install-foo reinstall-foo
foo=/path/to/foo
curdir=$(shell pwd)
install-foo: $(curdir)/foo/lib/foo.h $(curdir)/foo/include/foo-1.2.a etc.
$(curdir)/foo/lib/foo.h:
make reinstall-foo
$(curdir)/foo/include/foo-1.2.a:
make reinstall-foo
... (etc)
reinstall-foo:
cd $(foo); ./configure --prefix=$(curdir)/foo; make; make install
And this one will install once for each file in the library, but (after that), it will reinstall when one of the files is missing.
Finally, I have a bash approach that is only so-so, as it does it with bash rather than make:
// within install-foo:
-(not ((-f $(curdir)/foo/foo.h) and (-f $(curdir)/include/foo-1.2.a) and (etc.)) && really-install-foo
really-install-foo:
...etc.
The question is: what is a makefile design that will install the first time once, and any subsequent calls to make install-foo will cause foo to be installed only if one, more, or all of the library files are missing?
Related
Say my directory structure is this:
foo
foo/Makefile
foo/bar
Now say foo/Makefile has a make target baz.
I want to call make baz from foo/bar without creating another Makefile in the bar subdirectory. Is this possible?
GNU make has two important options for your situation: -f FILE is used to tell make which makefile(s) to use instead of the defaults and -C DIR tells make to change to directory DIR before reading the makefiles. How to use one or the other or both depends on your specific case. Note that -f is compliant with the POSIX standard while -C is an extension supported by GNU make. If -C is not supported by your own version of make and has no equivalent you will have to change the current directory yourself before invoking make, e.g. ( cd some/where; make...; ).
If you can build baz from foo/bar/, as suggested by Oo.oO, you can simply
make -f ../Makefile baz
make will run from foo/bar/ and build baz as indicated in ../Makefile.
If you must be in foo/ to build baz you should use:
make -C .. baz
make will change to .., that is, foo before reading the makefiles and as it will find here one of the defaults (Makefile) it will use it to discover how to build baz.
If you must be in another directory, e.g. the parent of foo/, you need both options and type:
make -C ../.. -f foo/Makefile baz
make will first change to ../.. (parent directory of foo/) and from here it will use foo/Makefile to discover how to build baz.
Basic steps leading up to the question:
cd linux-2.6.35.9/
make ARCH=x86 INSTALL_HDR_PATH=${PREFIX}/${TARGET} headers_install
cd ../
cd build-binutils/
sh ../binutils-2.28/configure --prefix=${PREFIX} --target=${TARGET}
make
make install
cd ../
cd build-gcc/
sh ../gcc-4.9.4/configure --prefix=${PREFIX} --target=${TARGET} --enable-languages=c,c++ --disable-multilib
make all-gcc
make install-gcc
cd ../
The problem that I am running into is that what ends up getting installed into ${PREFIX}/lib/gcc/${TARGET}/4.9.4/include-fixed/limits.h doesn't seem to be correct. Specifically, the "fixincludes" bit in building and installing GCC is expecting some directory called "sys-include" that was never put into place and when it's not, the aforementioned limits.h doesn't reference the associated syslimits.h (in the same directory).
If I look in the output of the build/install sequence there's a reference to building this file from components limitx.h, limity.h, and some other bits. This test fails and it just installs the "generic" limits.h that came with GCC (that doesn't include a reference to syslimits.h which uses GCC's #include_next directive to include ${PREFIX}/${TARGET}/include/limits.h that has actual stuff in it I need like NAME_MAX and PATH_MAX).
The bit that is missing from the file is:
/* This administrivia gets added to the beginning of limits.h
if the system has its own version of limits.h. */
/* We use _GCC_LIMITS_H_ because we want this not to match
any macros that the system's limits.h uses for its own purposes. */
#ifndef _GCC_LIMITS_H_ /* Terminated in limity.h. */
#define _GCC_LIMITS_H_
#ifndef _LIBC_LIMITS_H_
/* Use "..." so that we find syslimits.h only in this same directory. */
#include "syslimits.h"
#endif
So is there an option I'm not passing to GCC's configuration script or that I am not passing to something ahead of this step that would create the sys-include directory properly?
[EDIT]
TARGET=i686-redhat-linux (a target triple from "gcc -dumpmachine" on a build server we use for the project)
Possibly more helpful information(?): The packages were simply "wget" pulls from respective archives. I am building on an up-to-date Ubuntu 16.04 installation where I installed libgmp-dev and libmpfr-dev to avoid having to compile them with the compiler source code.
After more digging and trial-and-error I matched up some stuff I started with How to Build a GCC Cross-Compiler with information about an apparently deprecated option --with-headers for configuring GCC. (--with-headers=${PREFIX}/${TARGET}/include/linux) That worked but when I built the compiler support library it complained about missing bits/stdio_lim.h. I found another post here that talks about this problem (you have to go up in the thread a bit) and had mentioned the touching gnu/stubs.h thing from the first page I mentioned.
Added from my own comment below to note that you have to remove the ${PREFIX}/${TARGET}/sys-include directory that gets build after the make install-gcc step or else your normal C headers are going to conflict with the Linux Kernel-specific headers that get included in the search path by default.
Suffice it to say that, after applying a patch to the older Glibc I was using (2.11.3) the entire sequence ends up something like this:
export TARGET=i686-redhat-linux
export PREFIX=$(pwd)/output
export PATH=${PATH}:${PREFIX}/bin
mkdir build-binutils
mkdir build-gcc
mkdir build-glibc
cd linux-2.6.35.9/
make ARCH=x86 INSTALL_HDR_PATH=${PREFIX}/${TARGET} headers_install
cd ../
cd build-binutils/
sh ../binutils-2.28/configure --prefix=${PREFIX} --target=${TARGET}
make
make install
cd ../
cd build-gcc/
sh ../gcc-4.9.4/configure --prefix=${PREFIX} --target=${TARGET} --enable-languages=c,c++ --disable-multilib --with-headers=${PREFIX}/${TARGET}/include/linux
make all-gcc
make install-gcc
cd ../
rm --recursive --force ${PREFIX}/${TARGET}/sys-include
cd build-glibc/
sh ../glibc-2.11.3/configure --prefix=${PREFIX}/${TARGET} --build=$(gcc -dumpmachine) --host=${TARGET} --target=${TARGET} --disable-multilib libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes
make install-bootstrap-headers=yes install-headers
make csu/subdir_lib
install csu/crt1.o csu/crti.o csu/crtn.o ${PREFIX}/${TARGET}/lib
${TARGET}-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o ${PREFIX}/${TARGET}/lib/libc.so
touch ${PREFIX}/${TARGET}/include/gnu/stubs.h ${PREFIX}/${TARGET}/include/bits/stdio_lim.h
cd ../
cd build-gcc/
make all-target-libgcc
make install-target-libgcc
cd ../
cd build-glibc/
make
make install
cd ../
I don't see any pages that actually go to this depth (maybe the Preshing on Programming page isn't actually totally correct?) but I am going to test this configuration and make sure the software builds completely for the target without problems. (I did test NAME_MAX from limits.h in a file and it seemed to work just fine and dandy.)
I also don't really know that I need to put in the --disable-multilib thing but that seems to be what other pages are doing. That chain in the GCC mailing list talks about using --with-newlib or --disable-shared as options but people on the thread could not agree either of those were the correct solution.
If anyone has better insight into this I sure would appreciate a less hacky, more official solution to the problem.
In case anyone was wondering, the patch (there are two) to fix Glibc 2.11.3 was one custom fix for the configure script to work with GNU Make 4+:
sed -i 's/\(3.79\)/4.* | \1/' glibc-2.11.3/configure
... and an actual patch to two files in the library to fix i686 suport:
patch glibc-2.11.3/nptl/sysdeps/pthread/pt-initfini.c <<__EOF__
## -45,6 +45,11 ##
/* Embed an #include to pull in the alignment and .end directives. */
asm ("\n#include \"defs.h\"");
+asm ("\n#if defined __i686 && defined __ASSEMBLER__");
+asm ("\n#undef __i686");
+asm ("\n#define __i686 __i686");
+asm ("\n#endif");
+
/* The initial common code ends here. */
asm ("\n/*#HEADER_ENDS*/");
__EOF__
patch glibc-2.11.3/sysdeps/unix/sysv/linux/i386/sysdep.h <<__EOF__
## -29,6 +29,10 ##
#include <dl-sysdep.h>
#include <tls.h>
+#if defined __i686 && defined __ASSEMBLER__
+#undef __i686
+#define __i686 __i686
+#endif
/* For Linux we can use the system call table in the header file
/usr/include/asm/unistd.h
__EOF__
I got that last patch from here.
I have a project with a menuconfig configuration for which this I use several *_defconfig files as default configurations. These defconfig files are grouped for each project:
/
- projects
- projectA
- configs
- 32bit_defconfig
- 64bit_defconfig
- foo_defconfig
- projectB
- configs
- 32bit_defconfig
- 64bit_defconfig
- bar_defconfig
Now I would like to have a makefile, where I get the autocompletion for these defconfigs:
$ make projects/pr<TAB>
projects/projectA
projects/projectB
I thought about writing a Makefile like this:
projects/%/configs/%_defconfig: FORCE
echo $#
Currently the only thing which is working is this rule, where I have no autocompletion for the path:
# e.g. 'make projects/88000-000/configs/32bit_defconfig'
%_defconfig: FORCE
$(MAKE) -f tools/make/menuconfig.mk $#
PS: Autocompletion works for regular make targets.
You can use wildcards for this reason:
DEFCONFIGS=$(wildcard projects/*/configs/*_defconfig)
test: FORCE
echo $(DEFCONFIG)
$(DEFCONFIGS): FORCE
$(MAKE) -f tools/make/menuconfig.mk $#
First use the test-target to check whether your wildcard is working, then you can use autocompletion:
$ make <TAB>
all default install_toolchain
buildroot-menuconfig FORCE menuconfig
clean install projects/
$ make projects/<TAB>
92107-110/ BananaPro/
$
I have a autotool project where part of the source code is downloaded dynamically from the net (because of IP rights preventing direct redistribution) and then built.
I have a Makefile.am that works but I'm not happy about some of it's aspects.
Here it is:
INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS = -fPIC -Wall ${SYMBOL_VISIBILITY}
LIBVERSION=0:0:0
REFSRC_PATH=refsrc
REFSRC_SRC=refsrc/dtx.c refsrc/globdefs.c refsrc/host.c refsrc/mathhalf.c refsrc/sp_enc.c refsrc/sp_rom.c refsrc/vad.c refsrc/err_conc.c refsrc/homing.c refsrc/mathdp31.c refsrc/sp_dec.c refsrc/sp_frm.c refsrc/sp_sfrm.c
${REFSRC_PATH}/.downloaded:
./fetch_sources.py "${REFSRC_PATH}"
for f in `ls -1 "${REFSRC_PATH}"/*.{c,h}`; do \
sed -i -e"s/round/round_l2s/" "$$f"; \
done
touch $#
${REFSRC_PATH}/dtx.c: ${REFSRC_PATH}/.downloaded
lib_LTLIBRARIES = libgsmhr.la
libgsmhr_la_SOURCES = libgsmhr.c $(REFSRC_SRC)
clean-local:
-rm -rf ${REFSRC_PATH}
So essentially, libgsmhr.c is my main wrapper, then I download the source code in a refsrc/ subdirectory and patch it a little.
First problem is that in REFSRC_SRC I would have loved to use a $(addprefix ...) instead of repeating refsrc/ in front of each .c file. But that doesn't seem to work and autoreconf complains a little.
Failure details (when removing the refsrc/ prefix from REFSRC_SRC= and using $(addprefix ${REFSRC_PATH}/, ${REFSRC_SRC}) on the dependency list):
bash$ autoreconf -i
libgsmhr/Makefile.am:19: addprefix ${REFSRC_PATH}/, ${REFSRC_SRC}: non-POSIX variable name
libgsmhr/Makefile.am:19: (probably a GNU make extension)
(configure works fine)
bash$ make
...
make[2]: Entering directory `/tmp/ram/gapk.build/libgsmhr'
CC libgsmhr.lo
CCLD libgsmhr.la
make[2]: Leaving directory `/tmp/ram/gapk.build/libgsmhr'
...
(So as you see it didn't include any of the downloaded .c files, didn't even download them at all. The compile works because libgsmhr.c is a stub that doesn't use the symbols in those file yet)
Second problem is this rule:
${REFSRC_PATH}/dtx.c: ${REFSRC_PATH}/.downloaded
I have to explicitely list the first file (dtx.c) instead of using a wildcard like:
${REFSRC_PATH}/%.c: ${REFSRC_PATH}/.downloaded
If I try to use the wildcard, then autoreconf complains and also it just doesn't work ... (pattern doesn't match somehow).
Failure detail:
bash$ autoreconf -i
libgsmhr/Makefile.am:16: `%'-style pattern rules are a GNU make extension
(configure works fine)
bash$ make
...
make[2]: *** No rule to make target `refsrc/dtx.c', needed by `dtx.lo'. Stop.
...
Sylvain
You seem to be writing a makefile in GNUMake style, but actually running some other version of Make. If it's not obvious what autoreconf is calling, you could insert a rule in the makefile:
dummy:
#echo using $(MAKE)
$(MAKE) -v
If this theory proves correct, you can either persuade autoconf to use GNUMake, or write for the version it's using.
It is clear that the target is newer than the source from these two ls
comands:
[metaperl#andLinux ~/edan/pkg/gist.el] ls -l ../../wares/gist.el/gist.elc #target
-rw-r--r-- 1 metaperl metaperl 10465 Jul 18 10:56 ../../wares/gist.el/gist.elc
[metaperl#andLinux ~/edan/pkg/gist.el] ls -l yank/gist.el/gist.el #source
-rw-r--r-- 1 metaperl metaperl 13025 Jul 18 10:57 yank/gist.el/gist.el
[metaperl#andLinux ~/edan/pkg/gist.el]
However when I run makepp -v I am told that this rule depends not only
on the listed target, but also on the cd and mv commands.
makepplog: Targets
/home/metaperl/edan/wares/gist.el/gist.elc'
depend on/usr/local/bin/emacs',
/home/metaperl/edan/pkg/gist.el/yank/gist.el/gist.el',
/bin/mv'
What aspect of make logic dictates that the actions to produce the
target are part of the dependency chain of deciding on whether to make
the target?
To my mind, only the listed sources should affect whether or not the
target is rebuilt.
The entire makepp -v output is quite long, and exists at:
http://gist.github.com/480468
My makepp file:
include main.makepp
#VER
PKG := gist.el
URL := http://github.com/defunkt/$(PKG).git
TARGET := $(WARES)gist.el/gist.elc
$(TARGET) : yank/gist.el/gist.el
cd $(dir $(input)) && $(BYTECOMPILE) gist.el
mv $(dir $(input)) $(WARES)
perl {{
print 'github username: ';
my $username = <STDIN>;
print 'github API token: ';
my $api_token = <STDIN>;
system "git config --global github.user $username";
system "git config --global github.token $api_token";
use File::Butler;
my $lines = Butler('init.el', 'read');
my $loc = sprintf '%s%s', $EDAN_PKG, "$PKG/";
$lines =~ s/__LOC__/$loc/g;
$lines =~ s/__PKG__/$PKG/g;
Butler( $EDAN_EL, prepend => \$lines );
}}
yank/gist.el/gist.el : yank
cd yank && git clone http://github.com/defunkt/gist.el.git
yank:
mkdir yank
$(phony clean):
$(RM) -rf $(dir $(TARGET)) yank
With a standard make, the contents of the commands to make a target are not taken into account when deciding whether to rebuild the target. Only the dependencies are taken into account; this can go beyond the source if you have dependencies declared elsewhere.
You don't show your makeppfile, so I can't be sure, but the Parsing command... messages from makepp -v make me suspect that makepp behaves differently from standard make on this count.
makepp will rebuild a target if any of the dependencies have changed or if the command has changes. In your case, I suspect that either some of the variables that you use in the rule to make $(TARGET) have changed or that makepp is seeing that the commands are constructed dynamically and is automatically rebuilding the target. Try using the -m target_newer option to makepp to force it to use the old GNU make method (that is, only re-build if the source is newer than the target).
Link