Run MacOS sed on Linux 64 using nix-shell or nix shell - linux

Answering sed questions on SO I often come across the problem of "works on linux but not MacOS" is it possible to load a version of sed that runs on MacOS into a nix shell?
Currently using flakes I can obtain the latest gnused using:
nix shell nixpkgs#gnused
Is there a way to temporarily install a BSD/MacOS version of sed?

Not so long ago I looked into this problem; perhaps you can make use
of what I found.
Web searches show little demand for FreeBSD sed outside BSD so I
decided to get it (well, GET it) from
github
and build and test it on a recent Debian system. To do so I created
3 files (listed below):
adapt/local.c - support for non-GNU functions
adapt/local.h - ditto header file
Makefile - downloads, generates required files, runs 1 or 2 of
the test suites; refer to comments in header and near target test
On my system the executable builds without errors. To test it using
tests/multi_test.sh I ran
make test | tee multi_test.log | grep '^not ok' | tee multi_test.err.log
with 127 of 130 tests succeeding and 3 failing:
not ok 69 7.1 # Print and file routines
not ok 75 7.7 # w results
not ok 97 8.21 # \ in y command
These discrepancies, I think, are no more than what can be expected: #69
is triggered by differences in output by sed -n l, #75 by differences
in /usr/share/dict/words contents (testcase of limited portability),
and #97 goes away if using SHELL := /bin/bash in the makefile or using
printf '%s\n' 'a\b(c' instead of echo 'a\b(c' in the test script.
UPDATE 2021-11-24: #69 goes away with e.g.
LANG=en make test | grep '^not ok', causing the locale-dependent
library function iswprint()
in process.c#lputs() to return zero for characters 0xA0..0xFF. #75
can only succeed if the first 200 lines of /usr/share/dict/words are
identical to those used by the testcase author; I fail to see the
reasoning behind this. (end UPDATE)
Still on the to-do list:
Makefile's *.names variables are hard-coded, better to create
them dynamically; however, the names seem to change rarely for a
program with sed's history
support for the ATF
tests by tests/sed2_test.sh (currently ignored)
support for embedded ident strings in the executable (__FBSDID
macro currently ignored) rather than rely on a date in the man page for
version
info
./Makefile
Note that recipes aren't prefixed with the usual tab character here
but with > (at beginning of line) acting as a make operator
(.RECIPEPREFIX = >).
# desc:
# Download, build, test FreeBSD sed (dated 2020-06-10) on GNU/Linux
# compat:
# dash 0.5.10 GNU make 4.2.1 GNU wget 1.20 GNU gcc 9.3.0 man 2.9
# ref:
# https://www.freebsd.org/cgi/man.cgi?sed
# https://github.com/freebsd/freebsd-src/tree/main/usr.bin/sed
# https://github.com/joshuarubin/wcwidth9
# files:
# Makefile adapt/local.c adapt/local.h
# howto:
# make download
# make all
# (optional) make download.tests download.regress.multitest.out test
# (optional) cp $(exe) /usr/local/bin/bsdsed
# (optional) cp $(man.1) /usr/local/man/man1/bsdsed.1
# note:
# Mind the $(wgetFlags) and $(CFLAGS)
SHELL := /bin/sh
wgetFlags ?= --no-verbose --wait=1
# $(call wgetCmd,subtarget-name)
define wgetCmd =
wget $(wgetFlags) --no-host-directories --directory-prefix=$($1.ldir) \
-- $(addprefix $($1.url),$($1.names))
endef
#
hdrs := defs.h extern.h
srcs := misc.c compile.c process.c main.c
hdrx := wcwidth9.h
srcx := local.c
objs := $(patsubst %.c,%.o,$(srcs) $(srcx))
# test scripts expect an executable named 'sed'
exe := sed
man.1 := $(exe).1
man.ps := $(exe).ps
binaries := $(exe) $(man.1) $(man.ps)
#
subtargets := wcwidth9 sed tests regress.multitest.out
dnldtargets := $(addprefix download.,$(subtargets))
#
wcwidth9.url := https://github.com/joshuarubin/wcwidth9/raw/master/
wcwidth9.names := $(hdrx)
wcwidth9.ldir := ./
#
sed.url := https://github.com/freebsd/freebsd-src/raw/master/usr.bin/sed/
sed.names := POSIX sed.1 $(srcs) $(hdrs)
sed.ldir := ./
tests.url := $(sed.url)tests/
tests.names := \
hanoi.sed inplace_race_test.sh legacy_test.sh math.sed \
multi_test.sh regress.G.out regress.P.out regress.b2a.out \
regress.bcb.out regress.c0.out regress.c1.out regress.c2.out \
regress.c3.out regress.hanoi.out regress.icase1.out \
regress.icase2.out regress.icase3.out regress.icase4.out \
regress.in regress.math.out regress.not.out regress.psl.out \
regress.s3.out regress.s4.out regress.s5.out regress.sg.out \
regress.sh regress.y.out sed2_test.sh
tests.ldir := ./tests/
regress.multitest.out.url := $(sed.url)tests/regress.multitest.out/
regress.multitest.out.names := \
1.1 1.2 1.3 1.4 1.4.1 1.5 1.6 1.7 1.8 1.9 1.10 1.11 1.12 1.13 \
1.14 1.15 1.16 1.17 1.18 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 \
2.10 2.11 2.12 2.13 2.14 2.15 2.16 2.17 2.18 2.19 2.20 2.21 \
2.22 2.23 3.1 3.2 3.3 3.4 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 5.1 \
5.2 5.3 5.4 5.5 5.6 5.7 5.8 6.1 6.2 6.3 6.4 6.5 6.6 7.1 7.2 \
7.3 7.4 7.5 7.6 7.7 7.8 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 \
8.10 8.11 8.12 8.13 8.14 8.15 8.16 8.17 8.18 8.19 8.20 8.21 \
8.22 8.23 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9 9.10 9.11 9.12 \
9.13 9.14 9.15 9.16 9.17 9.18 9.19 9.20 9.21 9.22 9.23 9.24 \
9.25 9.26 9.27 9.28 9.29 9.30 9.31
regress.multitest.out.ldir := ./tests/regress.multitest.out/
.RECIPEPREFIX = >
.DELETE_ON_ERROR:
.PHONY: all clean realclean
all : $(binaries)
clean : ; rm -f -- $(objs) $(binaries)
realclean : clean
> rm -f -- local.c manpage.1 $(foreach T,$(subtargets),$(addprefix $($(T).ldir),$($(T).names)))
> rmdir --ignore-fail-on-non-empty -- \
$(patsubst %/,%,$(foreach T,$(subtargets),$(filter-out %. %./,$($(T).ldir))))
# notonbsd: enable modifications in extern.h and $(srcx)
# __FBSDID: don't embed RCS ID
$(objs) : CFLAGS += -Dnotonbsd -D__FBSDID\(s\)=
$(objs) : $(srcs) $(hdrs)
extern.h : adapt/local.h
> grep -q '^.ifdef\s*notonbsd' $# || { cat $# $< > $#.tmp && mv -f -- $#.tmp $# ; }
local.c : adapt/local.c
> cp $< $#
local.o : $(hdrx)
main.o : CFLAGS += -D__unreachable=__builtin_unreachable
$(exe) : $(objs)
> $(LINK.c) -o $# $^
> $(if $(DEBUG),,strip $#)
$(man.1) : manpage.1
> cp $< $#
%.ps : %.1
> man -l -t $< > $#
.PHONY : download.all $(dnldtargets) download
download.all : $(dnldtargets)
$(dnldtargets) :
> $(call wgetCmd,$(patsubst download.%,%,$#))
download : download.wcwidth9 download.sed
> mv -f sed.1 manpage.1
> touch adapt/local.h
.PHONY: test
# ! run after: make download.tests download.regress.multitest.out
# ! hint: make test | tee multi_test.log | grep '^not ok' | tee multi_test.err.log
# - set PATH so scripts invoke the new sed executable
# - run multi_test.sh (requires /usr/share/dict/words regress.multitest.out/*)
# - optionally run inplace_race_test.sh
# - ignore legacy_test.sh regress.* (require m4 regress.m4 hanoi.sed math.sed)
# - ignore sed2_test.sh (requires ATF, cf. https://github.com/freebsd/freebsd-src/tree/main/contrib/atf)
test : | /usr/share/dict/words
> cd $(patsubst %/,%,$(tests.ldir)); \
PATH="..:$$PATH"; \
$(SHELL) multi_test.sh \
$(if $(racetest),; $(SHELL) inplace_race_test.sh && rm -f file[0-9] file[0-9].prev)
./adapt/local.c
/* Support for non-GNU functions, cf. man.freebsd.org */
#ifdef notonbsd
#include <err.h>
#include <limits.h>
#include <regex.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include "defs.h"
#include "extern.h"
#include "wcwidth9.h" /* https://github.com/joshuarubin/wcwidth9 */
void
errc(int eval, int code, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
errno = code;
err(eval, fmt, args);
va_end(args);
}
char*
getprogname()
{
return (program_invocation_short_name);
}
int
wcwidth(wchar_t wc)
{
return wcwidth9(wc);
}
size_t
strlcpy(char *dst, const char *src, size_t dstsize)
{
return snprintf(dst, dstsize, "%s", src);
}
size_t
strlcat(char *dst, const char *src, size_t dstsize)
{
int dlen, slen, dslen, addlim;
dlen = strlen(dst);
slen = strlen(src);
dslen = dlen + slen;
addlim = (dstsize > dslen ? slen : dstsize - dlen - 1);
if ( addlim > 0 )
strncat(dst, src, addlim);
return dslen;
}
#endif /* notonbsd */
./adapt/local.h
/* To be appended to extern.h */
#ifdef notonbsd
extern char *program_invocation_short_name;
char *getprogname();
void errc(int eval, int code, const char *fmt, ...);
int wcwidth(wchar_t wc);
size_t strlcpy(char *dst, const char *src, size_t dstsize);
size_t strlcat(char *dst, const char *src, size_t dstsize);
#endif /* notonbsd */
UPDATE on 2022-01-07
Following Makefile to build macOS sed on a Debian system uses the
same ./adapt/local.c and ./adapt/local.h as listed above. At my end
make download all builds the executable without errors but warns about
an ignored return value of fchown if $(CFLAGS) contains -O3.
make download.TEST test downloads test files, generates and runs
test-edited.sh (a modified TEST/sed.test) which adjusts test
parameters and fixes a redirection issue. Test logs show that 113
(30+83) out of 115 (30+85) test cases succeed (30 in test_error(),
the rest numbered):
test 2.8 fails: sed -n -e '0p' lines1 is run by macOS sed (and
FreeBSD sed) but GNU sed says "invalid usage of line address 0"
test 7.1 fails, even when line continuation char.s are eliminated:
l command of macOS sed (and FreeBSD sed) outputs backslash as \
but POSIX.1-2017
(and GNU sed) says \\
Test 7.7 (involving /usr/share/dict/words) is an indication that
the equivalent FreeBSD sed testcase #75 (see above) should be run
against the local file, not one produced by the test author.
./Makefile
Note: recipe prefix is > (at beginning of line), not tab.
# desc:
# Download, build, test macOS sed (dated 2017-03-27) on GNU/Linux.
# compat:
# dash 0.5.10 GNU make 4.2.1 GNU wget 1.20.3 GNU gcc 9.3.0
# GNU sed 4.7 GNU coreutils 8.30 man 2.9.1
# ref:
# https://opensource.apple.com/source/text_cmds/text_cmds-106/sed/
# https://github.com/joshuarubin/wcwidth9
# see:
# Last sed manpage (dated May 10, 2005) captured by archive.org on Aug 8, 2017
# https://web.archive.org/web/20170808213955/https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/sed.1.html
# https://leancrew.com/all-this/2021/03/apple-and-links/
# https://opensource.apple.com/source/text_cmds/text_cmds-106/text_cmds.plist
# https://unix.stackexchange.com/questions/13711/differences-between-sed-on-mac-osx-and-other-standard-sed
# files:
# Makefile adapt/local.c adapt/local.h
# howto:
# make download
# make all
# (optional) make download.TEST test
# note:
# Mind the $(wgetFlags) and $(CFLAGS)
SHELL := /bin/sh
refsed ?= /usr/bin/sed --posix
wgetFlags ?= --no-verbose --wait=1
# $(call wgetCmd,subtarget-name)
define wgetCmd =
wget $(wgetFlags) --no-host-directories --directory-prefix=$($1.ldir) \
-- $(addprefix $($1.url),$($1.names))
endef
#
hdrs := defs.h extern.h
srcs := misc.c compile.c process.c main.c
hdrx := wcwidth9.h
srcx := local.c
objs := $(patsubst %.c,%.o,$(srcs) $(srcx))
exe := sed
#
sed.genfiles := $(exe) $(exe).1.gz $(exe).pdf
test.gendirs := ./sed.out/ ./nsed.out/
test.genfiles := test-edited.sh test.log test-diff.log $(addsuffix *,$(test.gendirs))
#
subtargets := wcwidth9 sed TEST
dnldtargets := $(addprefix download.,$(subtargets))
#
wcwidth9.url := https://github.com/joshuarubin/wcwidth9/raw/master/
wcwidth9.names := $(hdrx)
wcwidth9.ldir := ./
sed.url := https://opensource.apple.com/source/text_cmds/text_cmds-106/sed/
sed.names := POSIX sed.1 $(srcs) $(hdrs)
sed.ldir := ./
TEST.url := $(sed.url)TEST/
TEST.names := hanoi.sed math.sed sed.test
TEST.ldir := ./TEST/
.RECIPEPREFIX = >
.DELETE_ON_ERROR:
.PHONY: all testclean clean realclean
all : $(sed.genfiles)
testclean :
> rm -f -d -- $(test.genfiles) $(patsubst %/,%,$(test.gendirs))
clean : testclean
> rm -f -- $(objs) $(sed.genfiles)
realclean : clean
> rm -f -- local.c $(foreach T,$(subtargets),$(addprefix $($(T).ldir),$($(T).names)))
> rmdir --ignore-fail-on-non-empty -- $(patsubst %/,%, \
$(foreach T,$(subtargets),$(filter-out %. %./,$($(T).ldir))))
# notonbsd: enable modifications in extern.h and $(srcx)
# __FBSDID: don't embed RCS ID
$(objs) : CFLAGS += $(if $(DEBUG),,-s -O3) -Dnotonbsd -D__FBSDID\(s\)=
$(objs) : $(srcs) $(hdrs)
extern.h : adapt/local.h
> grep -q '^.ifdef\s*notonbsd' $# || { cat $# $< > $#.tmp && mv -f -- $#.tmp $# ; }
local.c : adapt/local.c
> cp $< $#
local.o : $(hdrx)
main.o : CFLAGS += -D__unreachable=__builtin_unreachable
$(exe) : $(objs)
> $(LINK.c) $^ -o $#
%.1.gz : %.1
> gzip -fk $<
%.ps : %.1
> man -l -t $< > $#
%.pdf : %.ps
> ps2pdf $< $#
.PHONY : download.all $(dnldtargets) download
download.all : $(dnldtargets)
$(dnldtargets) :
> $(call wgetCmd,$(patsubst download.%,%,$#))
download : download.wcwidth9 download.sed
> touch adapt/local.h
.PHONY: test
# run after: make download.TEST
# notes:
# test 2.8: GNU sed says "invalid usage of line address 0"
# test 7.1 fails, even when line continuation char.s are eliminated:
# `l` command of macOS sed (and BSD sed) outputs backslash as '\'
# but POSIX.1-2017 (and GNU sed) says `\\`
test : test-diff.log
> printf '## test results in "%s"\n' '$<' 1>&2
test-diff.log : test.log
> - diff -c $(test.gendirs) > $#
# notes:
# `LANG=en`: cause test 7.1 not to output unicode/widechar
# creates $(test.gendirs)
# all tests in test_error() are supposed to produce error output
test.log : test-edited.sh
> LANG=en $(SHELL) $< 1>$# 2>&1
> rm -f -- lines[1-4] script[1-2]
test-edited.sh : $(TEST.ldir)sed.test $(exe)
> $(refsed) \
-e '# main() : adjust test parameters' \
-e '/^.BASE=/ s,.*,BASE="$(refsed)",' \
-e '/^.TEST=/ s,.*,TEST="./$(exe)",' \
-e '# be silent' \
-e '/^.BSD=/ s,.*,BSD=0,' \
-e '/^.GNU=/ s,.*,GNU=0,' \
-e '/^.SUN=/ s,.*,SUN=0,' \
-e '# allow "sed --posix" as exename' \
-e '/^.tests / s,\(\$$[A-Z][A-Z]*\),"\1",g' \
-e '# comment out "diff -c"' \
-e '/^.diff -c/ s,^,#,' \
-e '# test_error(): fix stdin redirection' \
-e '/^.exec 0>&3 4>&1 5>&2/ s,0>&3,3<\&0,' \
-e '/^.exec 0>&3 1>&4 2>&5/ s,0>&3,0<\&3,' \
$< > $#
.PHONY : test-7.1-compare
# special case
test-7.1-compare : $(addsuffix .nolinecontinuation,$(wildcard $(addsuffix *_7.1,$(test.gendirs))))
> - diff -c $^
%.nolinecontinuation : %
> $(refsed) -e ':a' -e '/[^\\]\\$$/N; s/\\\n//; ta' < $< > $#
Possibly of interest:
$ apt-cache search '^freebsd'
ctfutils - FreeBSD CTF utilities
freebsd-buildutils - Utilities for building FreeBSD sources
freebsd-glue - Emulate a FreeBSD build environment
freebsd-manpages - Manual pages for a GNU/kFreeBSD system
freebsd-mk - FreeBSD makefile templates for bmake
libarchive-tools - FreeBSD implementations of 'tar' and 'cpio' and other archive tools
libfreebsd-glue-0 - FreeBSD glue environment (shared objects)
libipx2 - FreeBSD IPX address conversion support library
libsbuf6 - FreeBSD string buffer library
libutil-freebsd-9 - FreeBSD utility library

Related

Linking library (from assembly files) with main.c in Makefile

Im passionate about assembly and wanted to start coding from home on linux instead of mac I usually use.
I really struggle for 4 days about this issue.
you can find my makefile and clone repository at the following url:
<code>NAME = libfts.a
ASM_FILES = ft_isascii \
OS := $(shell uname)
ifeq ($(OS), Darwin)
ASM_COMPILER = ~/.brew/bin/nasm -f macho64 -g
else
ASM_COMPILER = nasm -f elf64 -g
endif
ASM_SRC_DIR = srcs/
ASM_OBJ_DIR_NAME = obj
ASM_OBJ_DIR = $(ASM_OBJ_DIR_NAME)/
ASM_OBJ := $(addsuffix .o,$(ASM_FILES))
ASM_OBJ := $(addprefix $(ASM_OBJ_DIR),$(ASM_OBJ))
TEST = maintest.out
TEST_FILES = maintest
C_COMPILER = clang -Wall -Werror -Wextra -O3
TEST_DIR_NAME = test
TEST_DIR = $(TEST_DIR_NAME)/
TEST_OBJ := $(addsuffix .o,$(TEST_FILES))
TEST_OBJ := $(addprefix $(TEST_DIR),$(TEST_OBJ))
OBJ_PATHS := $(ASM_OBJ) $(TEST_OBJ)
all: $(NAME)
$(NAME): $(ASM_OBJ)
ar rc $(NAME) $(ASM_OBJ)
test: re $(TEST_OBJ)
$(C_COMPILER) -L. $(NAME) $(TEST_OBJ) -o $(TEST)
$(ASM_OBJ): $(ASM_OBJ_DIR)%.o: $(ASM_SRC_DIR)%.s
#/bin/mkdir -p $(ASM_OBJ_DIR)
$(ASM_COMPILER) $< -o $#
$(TEST_OBJ): $(TEST_DIR)%.o: $(TEST_DIR)%.c
$(C_COMPILER) -c -I. $< -o $#
clean:
-/bin/rm -f $(OBJ_PATHS)
/usr/bin/find . -name "$(ASM_OBJ_DIR_NAME)" -maxdepth 1 -type d -empty -delete
fclean: clean
-/bin/rm -f $(NAME)
-/bin/rm -f $(TEST)
re: fclean all
.PHONY: all clean fclean re
I have this error message when I try "make test" on the linux:
test/maintest.o: In function `main':
test/maintest.c:(.text+0x33): undefined reference to `ft_isascii'
undefined reference to etc.
.h content:
#ifndef _LIBFTS
# define _LIBFTS
#include <stddef.h>
int ft_isascii(int c);
#endif
ft_isascii.s content:
global _ft_isascii
section .text
_ft_isascii: ; int ft_isascii
and edi, 0xffffff80 ; mask with the 128 firsts bits left to 0 as ASCII range from 0 to 7f in hexa (just below 80)
sete al ; SETE sets AL to 1 if above condition code means "equal", otherwise it sets AL to 0.
movzx eax, al
ret
I would REALLY be thanksful for any tips to solve this issue...
Regards,
There are two problems to be fixed:
First, on ELF targets (most Unixes except macOS), C functions are not decorated with an underscore. To fix your code, remove the leading underscore from all symbols. Make sure to remove it everywhere.
Second, the linker when looking at an archive (.a file) only picks files it needs right now to satisfy dependencies. So when you pass the archive before maintest.o, the linker doesn't take anything from the archive at all as it doesn't need any ft_... symbols at that point. These symbols are only needed once the linker has seen maintest.o. To fix this issue, move the $(NAME) operand to after $(TEST_OBJ). As a general rule of thumb, always place libraries after object files on the linker command line.
On macOS, you won't observe this problem because they use lld, the LLVM linker, which is a bit unconventional in that it defers the choice which objects to take out of archives until it has looked at the symbol tables of all operands, making your actually broken invocation work. Don't depend on this behaviour, please.

Qmake - doesn't copy file in linux

That code
defineTest(deployFiles) {
win32 {
to = $$shell_path($$3)
for(entry,1){
from = $$shell_path($$2/$$entry)
QMAKE_POST_LINK += $$quote(cmd /c copy /y $$from $$to $$escape_expand(\n\t))
PRE_TARGETDEPS += $$from
}
export(QMAKE_POST_LINK)
export(PRE_TARGETDEPS)
} else {
to = $$shell_path($$3)
for(entry,1){
from = $$shell_path($$2/$$entry)
QMAKE_POST_LINK += $$quote(cp $$from $$to $$escape_expand(\n\t))
PRE_TARGETDEPS += $$from
}
export(QMAKE_POST_LINK)
export(PRE_TARGETDEPS)
}
}
works only on Windows OS. Where $$from - file; $$to - directory.
And I unfortunately tried that:
QMAKE_POST_LINK += $$quote(xterm -e cp $$from $$to $$escape_expand(\n\t))
And unix instead else
If I put message($$QMAKE_POST_LINK) before export in linux block, in output I have message like that:
cp /home/user/QtProject/projects/Tools/qmldir /home/user/QtProject/qml/Tools/
cp /home/user/QtProject/projects/Tools/Tools.qml /home/user/QtProject/qml/Tools/
And output of grep "qmldir" -C 5 <my_build_dir>/Makefile (same as grep "Tools\.qml" -C 5 <my_build_dir>/Makefile) like that:
.c.o:
$(CC) -c $(CFLAGS) $(INCPATH) -o "$#" "$<"
####### Build rules
$(TARGET): /home/user/QtProject/projects/Tools/qmldir /home/user/QtProject/projects/Tools/Tools.qml $(OBJECTS)
Makefile: ../../../projects/Tools/Tools.pro /home/user/Qt/5.4/gcc_64/mkspecs/linux-g++/qmake.conf /home/user/Qt/5.4/gcc_64/mkspecs/features/spec_pre.prf \
/home/user/Qt/5.4/gcc_64/mkspecs/common/shell-unix.conf \
/home/user/Qt/5.4/gcc_64/mkspecs/common/unix.conf \
The project which does not work is of TEMPLATE type "aux", which is used when no compiler and no linker is involved. Thus the link command is empty.
Looks like QMAKE_POST_LINK is written only if there is a link command.
Makefile from app_sandbox.pro (TEMPLATE = app):
####### Build rules
$(TARGET): $(OBJECTS)
#test -d ../../bin/ || mkdir -p ../../bin/
$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
Makefile: ../../projects/app_sandbox/app_sandbox.pro ../../../Qt/5.4/gcc_64/mkspecs/linux-g++/qmake.conf ../../../Qt/5.4/gcc_64/mkspecs/features/spec_pre.prf \
Makefile from Controls.pro (TEMPLATE = aux):
####### Build rules
$(TARGET): /home/simon/nobackup/app_sandbox/projects/Design/Controls/qmldir /home/simon/nobackup/app_sandbox/projects/Design/Controls/TreeView.qml $(OBJECTS)
Makefile: ../../../projects/Design/Controls/Controls.pro ../../../../Qt/5.4/gcc_64/mkspecs/linux-g++/qmake.conf ../../../../Qt/5.4/gcc_64/mkspecs/features/spec_pre.prf \
As you can see, both specify dependencies for the target (after $(TARGET):) but there is no link command in the seconds Makefile.

Why can't CUDA's examples makefile find the CUDA libraries?

I'm running Arch Linux and have installed the cuda-sdk and cuda-toolkit from the repositories. I've compiled the libraries inside /opt/cuda-sdk/CUDALibraries fine.
No I go to compile the sdk examples by running make in /opt/cuda-sdk/C and get the following error:
# make
make[1]: Entering directory `/opt/cuda-sdk/C/common'
make[1]: Leaving directory `/opt/cuda-sdk/C/common'
make[1]: Entering directory `/opt/cuda-sdk/C/common'
make[1]: Leaving directory `/opt/cuda-sdk/C/common'
make[1]: Entering directory `/opt/cuda-sdk/C/common'
make[1]: Leaving directory `/opt/cuda-sdk/C/common'
make[1]: Entering directory `/opt/cuda-sdk/shared'
make[1]: Leaving directory `/opt/cuda-sdk/shared'
make[1]: Entering directory `/opt/cuda-sdk/C/src/newdelete'
make[1]: Leaving directory `/opt/cuda-sdk/C/src/newdelete'
make[1]: Entering directory `/opt/cuda-sdk/C/src/simpleTextureDrv'
/usr/bin/ld: cannot find -lcuda
collect2: error: ld returned 1 exit status
make[1]: *** [../../bin/linux/release/simpleTextureDrv] Error 1
make[1]: Leaving directory `/opt/cuda-sdk/C/src/simpleTextureDrv'
make: *** [src/simpleTextureDrv/Makefile.ph_build] Error 2
The Makefile itself essentially seems to just include the file /opt/cuda-sdk/C/common/common.mk, which is:
################################################################################
#
# Copyright 1993-2011 NVIDIA Corporation. All rights reserved.
#
# NVIDIA Corporation and its licensors retain all intellectual property and
# proprietary rights in and to this software and related documentation.
# Any use, reproduction, disclosure, or distribution of this software
# and related documentation without an express license agreement from
# NVIDIA Corporation is strictly prohibited.
#
# Please refer to the applicable NVIDIA end user license agreement (EULA)
# associated with this source code for terms and conditions that govern
# your use of this NVIDIA software.
#
################################################################################
#
# Common build script for CUDA source projects for Linux and Mac platforms
#
################################################################################
.SUFFIXES : .cu .cu_dbg.o .c_dbg.o .cpp_dbg.o .cu_rel.o .c_rel.o .cpp_rel.o .cubin .ptx
# Add new SM Versions here as devices with new Compute Capability are released
SM_VERSIONS := 10 11 12 13 20 21 30
CUDA_INSTALL_PATH ?= /opt/cuda-toolkit
ifdef cuda-install
CUDA_INSTALL_PATH := $(cuda-install)
endif
# detect OS
OSUPPER = $(shell uname -s 2>/dev/null | tr [:lower:] [:upper:])
OSLOWER = $(shell uname -s 2>/dev/null | tr [:upper:] [:lower:])
# 'linux' is output for Linux system, 'darwin' for OS X
DARWIN = $(strip $(findstring DARWIN, $(OSUPPER)))
ifneq ($(DARWIN),)
SNOWLEOPARD = $(strip $(findstring 10.6, $(shell egrep "<string>10\.6" /System/Library/CoreServices/SystemVersion.plist)))
LION = $(strip $(findstring 10.7, $(shell egrep "<string>10\.7" /System/Library/CoreServices/SystemVersion.plist)))
endif
# detect 32-bit or 64-bit platform
HP_64 = $(shell uname -m | grep 64)
OSARCH= $(shell uname -m)
# Basic directory setup for SDK
# (override directories only if they are not already defined)
SRCDIR ?=
ROOTDIR ?= ..
ROOTBINDIR ?= $(ROOTDIR)/../bin
BINDIR ?= $(ROOTBINDIR)/$(OSLOWER)
ROOTOBJDIR ?= obj
LIBDIR := $(ROOTDIR)/../lib
COMMONDIR := $(ROOTDIR)/../common
SHAREDDIR := $(ROOTDIR)/../../shared/
# Compilers
NVCC := $(CUDA_INSTALL_PATH)/bin/nvcc
CXX := g++ -fPIC
CC := gcc -fPIC
LINK := g++ -fPIC
# Includes
INCLUDES += -I. -I$(CUDA_INSTALL_PATH)/include -I$(COMMONDIR)/inc -I$(SHAREDDIR)/inc
# Warning flags
CXXWARN_FLAGS := \
-W -Wall \
-Wimplicit \
-Wswitch \
-Wformat \
-Wchar-subscripts \
-Wparentheses \
-Wmultichar \
-Wtrigraphs \
-Wpointer-arith \
-Wcast-align \
-Wreturn-type \
-Wno-unused-function \
$(SPACE)
CWARN_FLAGS := $(CXXWARN_FLAGS) \
-Wstrict-prototypes \
-Wmissing-prototypes \
-Wmissing-declarations \
-Wnested-externs \
-Wmain \
# architecture flag for nvcc and gcc compilers build
CUBIN_ARCH_FLAG :=
CXX_ARCH_FLAGS :=
NVCCFLAGS :=
LIB_ARCH := $(OSARCH)
# Determining the necessary Cross-Compilation Flags
# 32-bit OS, but we target 64-bit cross compilation
ifeq ($(x86_64),1)
NVCCFLAGS += -m64
LIB_ARCH = x86_64
ifneq ($(DARWIN),)
CXX_ARCH_FLAGS += -arch x86_64
else
CXX_ARCH_FLAGS += -m64
endif
else
# 64-bit OS, and we target 32-bit cross compilation
ifeq ($(i386),1)
NVCCFLAGS += -m32
LIB_ARCH = i386
ifneq ($(DARWIN),)
CXX_ARCH_FLAGS += -arch i386
else
CXX_ARCH_FLAGS += -m32
endif
else
ifeq "$(strip $(HP_64))" ""
LIB_ARCH = i386
NVCCFLAGS += -m32
ifneq ($(DARWIN),)
CXX_ARCH_FLAGS += -arch i386
else
CXX_ARCH_FLAGS += -m32
endif
else
LIB_ARCH = x86_64
NVCCFLAGS += -m64
ifneq ($(DARWIN),)
CXX_ARCH_FLAGS += -arch x86_64
else
CXX_ARCH_FLAGS += -m64
endif
endif
endif
endif
# Compiler-specific flags (by default, we always use sm_10, sm_20, and sm_30), unless we use the SMVERSION template
GENCODE_SM10 := -gencode=arch=compute_10,code=\"sm_10,compute_10\"
GENCODE_SM20 := -gencode=arch=compute_20,code=\"sm_20,compute_20\"
GENCODE_SM30 := -gencode=arch=compute_30,code=\"sm_30,compute_30\"
CXXFLAGS += $(CXXWARN_FLAGS) $(CXX_ARCH_FLAGS)
CFLAGS += $(CWARN_FLAGS) $(CXX_ARCH_FLAGS)
LINKFLAGS +=
LINK += $(LINKFLAGS) $(CXX_ARCH_FLAGS)
# This option for Mac allows CUDA applications to work without requiring to set DYLD_LIBRARY_PATH
ifneq ($(DARWIN),)
LINK += -Xlinker -rpath $(CUDA_INSTALL_PATH)/lib
endif
# Common flags
COMMONFLAGS += $(INCLUDES) -DUNIX
# If we are enabling GPU based debugging, then we want to use -G, warning that this
# May have a significant impact on GPU device code, since optimizations are turned off
ifeq ($(gpudbg),1)
NVCCFLAGS += -G
dbg = $(gpudbg)
endif
# Debug/release configuration
ifeq ($(dbg),1)
COMMONFLAGS += -g
NVCCFLAGS += -D_DEBUG
CXXFLAGS += -D_DEBUG
CFLAGS += -D_DEBUG
BINSUBDIR := debug
LIBSUFFIX := D
else
COMMONFLAGS += -O2
BINSUBDIR := release
LIBSUFFIX :=
NVCCFLAGS += --compiler-options -fno-strict-aliasing
CXXFLAGS += -fno-strict-aliasing
CFLAGS += -fno-strict-aliasing
endif
# architecture flag for cubin build
CUBIN_ARCH_FLAG :=
# OpenGL is used or not (if it is used, then it is necessary to include GLEW)
ifeq ($(USEGLLIB),1)
ifneq ($(DARWIN),)
OPENGLLIB := -L/System/Library/Frameworks/OpenGL.framework/Libraries
OPENGLLIB += -lGL -lGLU $(COMMONDIR)/lib/$(OSLOWER)/libGLEW.a
else
# this case for linux platforms
OPENGLLIB := -lGL -lGLU -lX11 -lXi -lXmu
# check if x86_64 flag has been set, otherwise, check HP_64 is i386/x86_64
ifeq ($(x86_64),1)
OPENGLLIB += -lGLEW_x86_64 -L/usr/X11R6/lib64
else
ifeq ($(i386),)
ifeq "$(strip $(HP_64))" ""
OPENGLLIB += -lGLEW -L/usr/X11R6/lib
else
OPENGLLIB += -lGLEW_x86_64 -L/usr/X11R6/lib64
endif
endif
endif
# check if i386 flag has been set, otehrwise check HP_64 is i386/x86_64
ifeq ($(i386),1)
OPENGLLIB += -lGLEW -L/usr/X11R6/lib
else
ifeq ($(x86_64),)
ifeq "$(strip $(HP_64))" ""
OPENGLLIB += -lGLEW -L/usr/X11R6/lib
else
OPENGLLIB += -lGLEW_x86_64 -L/usr/X11R6/lib64
endif
endif
endif
endif
endif
ifeq ($(USEGLUT),1)
ifneq ($(DARWIN),)
OPENGLLIB += -framework GLUT
else
ifeq ($(x86_64),1)
OPENGLLIB += -lglut -L/usr/lib64
endif
ifeq ($(i386),1)
OPENGLLIB += -lglut -L/usr/lib
endif
ifeq ($(x86_64),)
ifeq ($(i386),)
OPENGLLIB += -lglut
endif
endif
endif
endif
ifeq ($(USEPARAMGL),1)
PARAMGLLIB := -lparamgl_$(LIB_ARCH)$(LIBSUFFIX)
endif
ifeq ($(USERENDERCHECKGL),1)
RENDERCHECKGLLIB := -lrendercheckgl_$(LIB_ARCH)$(LIBSUFFIX)
endif
ifeq ($(USENVCUVID), 1)
ifneq ($(DARWIN),)
NVCUVIDLIB := -L../../common/lib/darwin -lnvcuvid
endif
endif
# Libs
ifneq ($(DARWIN),)
LIB := -L$(CUDA_INSTALL_PATH)/lib -L$(LIBDIR) -L$(COMMONDIR)/lib/$(OSLOWER) -L$(SHAREDDIR)/lib $(NVCUVIDLIB)
else
ifeq "$(strip $(HP_64))" ""
ifeq ($(x86_64),1)
LIB := -L$(CUDA_INSTALL_PATH)/lib64 -L$(LIBDIR) -L$(COMMONDIR)/lib/$(OSLOWER) -L$(SHAREDDIR)/lib
else
LIB := -L$(CUDA_INSTALL_PATH)/lib -L$(LIBDIR) -L$(COMMONDIR)/lib/$(OSLOWER) -L$(SHAREDDIR)/lib
endif
else
ifeq ($(i386),1)
LIB := -L$(CUDA_INSTALL_PATH)/lib -L$(LIBDIR) -L$(COMMONDIR)/lib/$(OSLOWER) -L$(SHAREDDIR)/lib
else
LIB := -L$(CUDA_INSTALL_PATH)/lib64 -L$(LIBDIR) -L$(COMMONDIR)/lib/$(OSLOWER) -L$(SHAREDDIR)/lib
endif
endif
endif
# If dynamically linking to CUDA and CUDART, we exclude the libraries from the LIB
ifeq ($(USECUDADYNLIB),1)
LIB += ${OPENGLLIB} $(PARAMGLLIB) $(RENDERCHECKGLLIB) ${LIB} -ldl -rdynamic
else
# static linking, we will statically link against CUDA and CUDART
ifeq ($(USEDRVAPI),1)
LIB += -lcuda ${OPENGLLIB} $(PARAMGLLIB) $(RENDERCHECKGLLIB) ${LIB}
else
ifeq ($(emu),1)
LIB += -lcudartemu
else
LIB += -lcudart
endif
LIB += ${OPENGLLIB} $(PARAMGLLIB) $(RENDERCHECKGLLIB) ${LIB}
endif
endif
ifeq ($(USECUFFT),1)
ifeq ($(emu),1)
LIB += -lcufftemu
else
LIB += -lcufft
endif
endif
ifeq ($(USECUBLAS),1)
ifeq ($(emu),1)
LIB += -lcublasemu
else
LIB += -lcublas
endif
endif
ifeq ($(USECURAND),1)
LIB += -lcurand
endif
ifeq ($(USECUSPARSE),1)
LIB += -lcusparse
endif
# Lib/exe configuration
# Lib/exe configuration
# Lib/exe configuration
ifneq ($(STATIC_LIB),)
TARGETDIR := $(LIBDIR)
TARGET := $(subst .a,_$(LIB_ARCH)$(LIBSUFFIX).a,$(LIBDIR)/$(STATIC_LIB))
LINKLINE = ar rucv $(TARGET) $(OBJS)
else
ifneq ($(OMIT_CUTIL_LIB),1)
LIB += -lcutil_$(LIB_ARCH)$(LIBSUFFIX)
endif
ifneq ($(OMIT_SHRUTIL_LIB),1)
LIB += -lshrutil_$(LIB_ARCH)$(LIBSUFFIX)
endif
# Device emulation configuration
ifeq ($(emu), 1)
NVCCFLAGS += -deviceemu
CUDACCFLAGS +=
BINSUBDIR := emu$(BINSUBDIR)
# consistency, makes developing easier
CXXFLAGS += -D__DEVICE_EMULATION__
CFLAGS += -D__DEVICE_EMULATION__
endif
TARGETDIR := $(BINDIR)/$(BINSUBDIR)
TARGET := $(TARGETDIR)/$(EXECUTABLE)
LINKLINE = $(LINK) -o $(TARGET) $(OBJS) $(LIB)
endif
# check if verbose
ifeq ($(verbose), 1)
VERBOSE :=
else
VERBOSE := #
endif
################################################################################
# Check for input flags and set compiler flags appropriately
################################################################################
ifeq ($(fastmath), 1)
NVCCFLAGS += -use_fast_math
endif
ifeq ($(keep), 1)
NVCCFLAGS += -keep
NVCC_KEEP_CLEAN := *.i* *.cubin *.cu.c *.cudafe* *.fatbin.c *.ptx
endif
ifdef maxregisters
NVCCFLAGS += -maxrregcount $(maxregisters)
endif
ifeq ($(ptxas), 1)
NVCCFLAGS += --ptxas-options=-v
endif
# Add cudacc flags
NVCCFLAGS += $(CUDACCFLAGS)
# Add common flags
NVCCFLAGS += $(COMMONFLAGS)
CXXFLAGS += $(COMMONFLAGS)
CFLAGS += $(COMMONFLAGS)
ifeq ($(nvcc_warn_verbose),1)
NVCCFLAGS += $(addprefix --compiler-options ,$(CXXWARN_FLAGS))
NVCCFLAGS += --compiler-options -fno-strict-aliasing
endif
################################################################################
# Set up object files
################################################################################
OBJDIR := $(ROOTOBJDIR)/$(LIB_ARCH)/$(BINSUBDIR)
OBJS += $(patsubst %.cpp,$(OBJDIR)/%.cpp.o,$(notdir $(CCFILES)))
OBJS += $(patsubst %.c,$(OBJDIR)/%.c.o,$(notdir $(CFILES)))
OBJS += $(patsubst %.cu,$(OBJDIR)/%.cu.o,$(notdir $(CUFILES)))
################################################################################
# Set up cubin output files
################################################################################
CUBINDIR := $(SRCDIR)data
CUBINS += $(patsubst %.cu,$(CUBINDIR)/%.cubin,$(notdir $(CUBINFILES)))
################################################################################
# Set up PTX output files
################################################################################
PTXDIR := $(SRCDIR)data
PTXBINS += $(patsubst %.cu,$(PTXDIR)/%.ptx,$(notdir $(PTXFILES)))
################################################################################
# Rules
################################################################################
$(OBJDIR)/%.c.o : $(SRCDIR)%.c $(C_DEPS)
$(VERBOSE)$(CC) $(CFLAGS) -o $# -c $<
$(OBJDIR)/%.cpp.o : $(SRCDIR)%.cpp $(C_DEPS)
$(VERBOSE)$(CXX) $(CXXFLAGS) -o $# -c $<
# Default arch includes gencode for sm_10, sm_20, sm_30, and other archs from GENCODE_ARCH declared in the makefile
$(OBJDIR)/%.cu.o : $(SRCDIR)%.cu $(CU_DEPS)
$(VERBOSE)$(NVCC) $(GENCODE_SM10) $(GENCODE_ARCH) $(GENCODE_SM20) $(GENCODE_SM30) $(NVCCFLAGS) $(SMVERSIONFLAGS) -o $# -c $<
# Default arch includes gencode for sm_10, sm_20, sm_30, and other archs from GENCODE_ARCH declared in the makefile
$(CUBINDIR)/%.cubin : $(SRCDIR)%.cu cubindirectory
$(VERBOSE)$(NVCC) $(GENCODE_SM10) $(GENCODE_ARCH) $(GENCODE_SM20) $(GENCODE_SM30) $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $(SMVERSIONFLAGS) -o $# -cubin $<
$(PTXDIR)/%.ptx : $(SRCDIR)%.cu ptxdirectory
$(VERBOSE)$(NVCC) $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $(SMVERSIONFLAGS) -o $# -ptx $<
#
# The following definition is a template that gets instantiated for each SM
# version (sm_10, sm_13, etc.) stored in SMVERSIONS. It does 2 things:
# 1. It adds to OBJS a .cu_sm_XX.o for each .cu file it finds in CUFILES_sm_XX.
# 2. It generates a rule for building .cu_sm_XX.o files from the corresponding
# .cu file.
#
# The intended use for this is to allow Makefiles that use common.mk to compile
# files to different Compute Capability targets (aka SM arch version). To do
# so, in the Makefile, list files for each SM arch separately, like so:
# This will be used over the default rule abov
#
# CUFILES_sm_10 := mycudakernel_sm10.cu app.cu
# CUFILES_sm_12 := anothercudakernel_sm12.cu
#
define SMVERSION_template
#OBJS += $(patsubst %.cu,$(OBJDIR)/%.cu_$(1).o,$(notdir $(CUFILES_$(1))))
OBJS += $(patsubst %.cu,$(OBJDIR)/%.cu_$(1).o,$(notdir $(CUFILES_sm_$(1))))
$(OBJDIR)/%.cu_$(1).o : $(SRCDIR)%.cu $(CU_DEPS)
# $(VERBOSE)$(NVCC) -o $$# -c $$< $(NVCCFLAGS) $(1)
$(VERBOSE)$(NVCC) -gencode=arch=compute_$(1),code=\"sm_$(1),compute_$(1)\" $(GENCODE_SM20) $(GENCODE_SM30) -o $$# -c $$< $(NVCCFLAGS)
endef
# This line invokes the above template for each arch version stored in
# SM_VERSIONS. The call function invokes the template, and the eval
# function interprets it as make commands.
$(foreach smver,$(SM_VERSIONS),$(eval $(call SMVERSION_template,$(smver))))
$(TARGET): makedirectories $(OBJS) $(CUBINS) $(PTXBINS) Makefile
$(VERBOSE)$(LINKLINE)
cubindirectory:
$(VERBOSE)mkdir -p $(CUBINDIR)
ptxdirectory:
$(VERBOSE)mkdir -p $(PTXDIR)
makedirectories:
$(VERBOSE)mkdir -p $(LIBDIR)
$(VERBOSE)mkdir -p $(OBJDIR)
$(VERBOSE)mkdir -p $(TARGETDIR)
tidy :
$(VERBOSE)find . | egrep "#" | xargs rm -f
$(VERBOSE)find . | egrep "\~" | xargs rm -f
clean : tidy
$(VERBOSE)rm -f *.stub.c *.gpu *.cu.cpp *.i *.ii
$(VERBOSE)rm -f *.cubin *.ptx *.fatbin.c *.hash
$(VERBOSE)rm -f *.cudafe1.c *.cudafe2.c *.cudafe1.cpp *.cudafe2.cpp
$(VERBOSE)rm -f $(OBJS)
$(VERBOSE)rm -f $(CUBINS)
$(VERBOSE)rm -f $(PTXBINS)
$(VERBOSE)rm -f $(TARGET)
$(VERBOSE)rm -f $(NVCC_KEEP_CLEAN)
$(VERBOSE)rm -f $(ROOTBINDIR)/$(OSLOWER)/$(BINSUBDIR)/*.ppm
$(VERBOSE)rm -f $(ROOTBINDIR)/$(OSLOWER)/$(BINSUBDIR)/*.pgm
$(VERBOSE)rm -f $(ROOTBINDIR)/$(OSLOWER)/$(BINSUBDIR)/*.bin
$(VERBOSE)rm -f $(ROOTBINDIR)/$(OSLOWER)/$(BINSUBDIR)/*.bmp
$(VERBOSE)rm -f $(ROOTBINDIR)/$(OSLOWER)/$(BINSUBDIR)/*.txt
$(VERBOSE)rm -f $(CUBINDIR)/*.cubin $(PTXDIR)/*.ptx
$(VERBOSE)rm -rf $(ROOTOBJDIR)
$(VERBOSE)rm -rf $(LIBDIR)
$(VERBOSE)rm -rf $(OBJDIR)
$(VERBOSE)rm -rf $(TARGETDIR)
clobber : clean
$(VERBOSE)rm -rf $(COMMONDIR)/lib/*.a
$(VERBOSE)rm -rf $(SHAREDDIR)/lib/*.a
$(VERBOSE)rm -rf $(COMMONDIR)/obj
$(VERBOSE)rm -rf $(SHAREDDIR)/obj
The output of echo $LD_LIBRARY_PATH is blank.
I have checked for libcuda and can find it where I think it should be:
# ls /usr/lib | grep libcuda
libcuda.so.1
libcuda.so.304.32
Is there something obvious I need to do to get these to compile? Is this a problem with the CUDA makefile or with my system?
The answer was suggested in comments, and the OP found the solution:
I added a symlink:
ln -s /usr/lib/libcuda.so.1 /usr/lib/libcuda.so
and it compiled fine.

make: -c: Command not found

First of all, I'm trying to get used to makefiles but yet I#m new with this. The following file is supposed to, first, compile all ./src/*.cpp files to ./src/*.o (where the filename survives) and afterwards complete compilation with simulation.cpp and linking the whole stuff together. Now, make returns the error message:
make: -c: Command not found
I have literally no clue how to proceed! Would the wildcard-construct even work in the way desired? Thanks a lot for your effort!
#basic stuff
TRUE = 1
FALSE = 0
SHELL := #!/bin/bash
# path names
SRCPATH = ./src/
CLEANPATH = ./res/ \
./crash/
# source files.
MAIN = simulation.cpp
OBJS = $(wildcard $(SRCPATH)*.o)
SRCS = $(wildcard $(SRCPATH)*.cpp)
INCLUDES = $(wildcard $(SRCPATH)*.h)
#GLOBAL MACROS PASSED TO PROGRAM!
MODEL_MRT = $(TRUE) #if true model used is MRT else SRT
PARALLEL = $(TRUE)
GRAVITY = $(TRUE)
# output file name
OUT = simulation
# C++ compiler flags (-g -O2 -Wall)
CXXFLAGS = -g -Wall -O -fopenmp
CXXDEFINES = -D MODEL=$(MODEL_MRT) -D PARALLEL=$(PARALLEL) -D GRAVITY=$(GRAVITY)
# compiler
CXX = g++
$(OUT) : $(OBJS)
$(CXX) $(CXXFLAGS) $(MAIN) $(OBJS) $(CXXDEFINES) -o $(OUT)
$(OBJS) : $(SRCS) $(INCLUDES)
$(CXX) $(CXXFLAGS) -c $(SRCS) -o $(OBJS)
clean : $(OUT)
rm $(OBJS)
rm $(CLEANPATH)/*.*
run : $(OUT) clean
./$(OUT)
.PHONY: clean run
You're tricking make with your SHELL variable, it sees is at empty as it is just a comment.
Change
SHELL := #!/bin/bash
to
SHELL := /bin/bash
This line:
SHELL := #!/bin/bash
is incorrect.
Your makefile should work perfectly well if you leave that line out altogether. If you do need something there, try
SHELL := /bin/bash

Problem with a loop inside makefile

I am trying to implement the logic to display the progress of the build in a makefile.
I can successfully print it for the target "simple" in the makefile cascaded herewith. However when it comes to another target "for" in the makefile, something goes wrong and I am not able to figure out what it is.
Any help would be really appreciated.
## BUILD is initially undefined
ifndef BUILD
# T estimates how many targets we are building by replacing BUILD with a special string
T := $(shell $(MAKE) progress --no-print-directory \
-nrRf $(firstword $(MAKEFILE_LIST)) \
BUILD="COUNTTHIS" | grep -c "COUNTTHIS")
## N is the target number
N := x
## incrementing counter
C = $(words $N)$(eval N := x $N)$(shell export $N)
## BUILD is now defined to show the progress, this also avoids redefining T in loop
BUILD = echo "`expr " [\`expr $C '*' 100 / $T\`" : '.*\(....\)$$'`%]"
endif
MODULE_LIST = module1
MODULE_LIST := $(MODULE_LIST) module2
MODULE_LIST := $(MODULE_LIST) module3
MODULE_LIST := $(MODULE_LIST) module4
MODULE_LIST := $(MODULE_LIST) module5
progress:
#$(BUILD)
#$(BUILD)
#$(BUILD)
#$(BUILD)
#$(BUILD)
simple:
# T=5 and C increases for every access
#$(BUILD) "Cleaning Module \"module1\""
#sleep 0.1
#$(BUILD) "Cleaning Module \"module2\""
#sleep 0.1
#$(BUILD) "Cleaning Module \"module3\""
#sleep 0.1
#$(BUILD) "Cleaning Module \"module4\""
#sleep 0.1
#$(BUILD) "Cleaning Module \"module5\""
#sleep 0.1
for:
# T=1 and C increases for every access but not inside the for loop
#for MODULE in $(MODULE_LIST); do \
$(BUILD) "Cleaning Module \"$$MODULE\"" ; \
sleep 0.1 ; \
done
As you noted in your comment, the problem is that the for loop executes inside the shell, and so does not update the Makefile's variables (or at least not more than once when Make builds the command string up by evaluating the variable references inside it).
The only feasible solution I can see is to move your loop construct into the Makefile. Try this:
## PRINT_PROGRESS is initially undefined
ifndef PRINT_PROGRESS
# T estimates how many targets we are building by replacing PRINT_PROGRESS with a special string
T := $(shell $(MAKE) $(MAKECMDGOALS) --no-print-directory \
-rRf $(firstword $(MAKEFILE_LIST)) \
PRINT_PROGRESS="echo COUNTTHIS" BUILD="test x ||" | grep -c "COUNTTHIS")
N := 1
## PRINT_PROGRESS is now defined to show the progress and update N
PRINT_PROGRESS = echo "`expr " [\`expr $N '*' 100 / $T\`" : '.*\(....\)$$'`%]"$(eval N := $(shell expr $N + 1))
endif
ifndef BUILD
BUILD := #blank
endif
MODULE_LIST = module1
MODULE_LIST += module2
MODULE_LIST += module3
MODULE_LIST += module4
MODULE_LIST += module5
simple:
# T=5 and C increases for every access
#$(PRINT_PROGRESS) "Cleaning Module \"module1\""
#$(BUILD) { sleep 0.1 ; echo "doing some work" ; }
#$(PRINT_PROGRESS) "Cleaning Module \"module2\""
#$(BUILD) { sleep 0.1 ; echo "doing some work" ; }
#$(PRINT_PROGRESS) "Cleaning Module \"module3\""
#$(BUILD) { sleep 0.1 ; echo "doing some work" ; }
#$(PRINT_PROGRESS) "Cleaning Module \"module4\""
#$(BUILD) { sleep 0.1 ; echo "doing some work" ; }
#$(PRINT_PROGRESS) "Cleaning Module \"module5\""
#$(BUILD) { sleep 0.1 ; echo "doing some work" ; }
for:
#$(foreach MODULE,$(MODULE_LIST),\
$(PRINT_PROGRESS) "Cleaning Module \"$(MODULE)\"" ; \
$(BUILD) { \
sleep 0.1 ; \
echo "doing some work" ; \
} ; \
)
This includes a couple of other changes too.
A solution that seems plausible at first glance is to export N from the makefile and design the PRINT_PROGRESS command so that N is always updated as an environment variable. I couldn't find a way to make this work though, since it requires some way of getting the updated N value back into Make after the command has been written, so that separate commands still work.
Edit: Output when running the exact script above (with corrected tab indents), plus versions used:
jpab#oberon : /memtmp
$ make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for x86_64-pc-linux-gnu
jpab#oberon : /memtmp
$ bash --version
GNU bash, version 4.1.5(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
jpab#oberon : /memtmp
$ make
# T=5 and C increases for every access
[20%] Cleaning Module "module1"
doing some work
[40%] Cleaning Module "module2"
doing some work
[60%] Cleaning Module "module3"
doing some work
[80%] Cleaning Module "module4"
doing some work
[100%] Cleaning Module "module5"
doing some work
jpab#oberon : /memtmp
$ make for
[20%] Cleaning Module "module1"
doing some work
[40%] Cleaning Module "module2"
doing some work
[60%] Cleaning Module "module3"
doing some work
[80%] Cleaning Module "module4"
doing some work
[100%] Cleaning Module "module5"
doing some work

Resources