Target for make gives "nothing to be done" - linux

I have an issue with "make" (Oh, the horror!).
We're trying to migrate some COBOL code from Windows to Linux. The compiler and such are from Micro Focus. Under Windows the code is developed with Micro Focus Net Express. Linux has Micro Focus Server Express as the equivalent. The programs are compiled and linked using "make" scripts.
So much for the background.
The problem is a "make" script that doesn't want to compile and link an executable under Linux. The targets look like this:
# HP INIT-Daten laden
#
datLoad$O: \
$(UI)/defretrn.cpy \
$(UI)/e12sy00s.cpy \
$(UI)/e12sy005.cpy \
$(UI)/e12sy006.cpy \
$(UI)/e12sy010.cpy \
$(UI)/e12sy013.cpy \
$(UI)/e12sy050.cpy \
$(UI)/e12db001.cpy \
$(UI)/e12db050.cpy \
$(UI)/evlg.cpy \
$(UI)/deffehl.cpy \
datLoad.xcbl $(FRC)
# #echo "dollar-O is \"$O\" in $#"
datLoad$X: $(LIBDSQL) datLoad$O \
$(LP)/evlg$O $(LP)/alock$O
$(LCOB) -o $(#:$X=) -e $(#:$X=) $(LCOBFLAGS) \
-d e12db001 -d e12db003 -d e12db012 \
-d e12sy005 -d e12sy006 -d e12sy009 \
-d e12sy010 -d e12sy012 -d e12sy013 \
-d e12sy050 \
-I EvLgSetCategory $(LP)/evlg$O \
-I ALckSetDebug $(LP)/alock$O \
$(LIBEXEEXT) "$(LIBXSQL)"
if [ -f $B/$# -a ! -w $B/$# ] ; then rm -f $B/$# ; fi
cp $# $B
To put this into context, $0=".o" (i.e. an object file extension). $(LCOB) is the link command. $X=".exe" (an executable ... just forget about the extension, we'll fix that in due course). All the other stuff relates to paths ==> not relevant to the issue at hand and, yes, they've all been checked and verified.
Ultimately, I am trying to get "make" to resolve a target called "datLoad.o".
Included is a second "make" script containing the following:
COBFLAGS = -cx # create object file
GNTFLAGS = -ug # create .gnt file
SOFLAGS = -z # create
LCOB = cob
...
.cbl$O:
$(CCOB) $(COBFLAGS) $*.cbl, $*$O, NUL, NUL
if [ -f $(LP)/$*$O -a ! -w $(LP)/$*$O ] ; then rm -f $(LP)/$*$O ; fi
cp $*$O $(LP)
The relevant part is the target which resolves to ".cbl.o:". Yes, that's the shorthand version and I don't really like it but I did not write this script. I'm assured that it really means *.o:*.cbl and other similar constructs in the script do work correctly.
With a simple "make" I get a link error:
> In function `cbi_entry_point': (.data+0x384): undefined reference to
> `datLoad' /tmp/cobwZipkt/%cob0.o: In function `main': (.text+0x28):
> undefined reference to `datLoad' make: *** [datLoad.exe] Error 1
That means datLoad.o was not created. If I do create it explicitly with:
cob -cx datload
Then "make" still gives the same error as above. Weird! However, what I really cannot understand is the response I get from "make datLoad.o" when the target does not exist:
make: Nothing to be done for `datLoad.o'.
I assumed (heaven help me) that the target "datLoad.o" would try to create the required target file if that file does not already exist. Am I going mad?
Sorry if this seems a bit obscure, I'm not sure how to phrase it better. If anybody has an idea what might be going on, I'd be really grateful...

Thank you Mad Scientist. Your tip was correct.
The included .mk contained a .SUFFIXES rule. The problem was that the $O was not being used consistently. $O was originally set to ".obj" for Windows. Under Linux it's ".o". However, the .SUFFIXES rule had the ".obj" hard coded into it, so of course the ".o" targets were not being recognised. I replaced the hard coded suffix with the $O variable and it now works.
Achim

Related

Creating variable from bash command output in makefile

Hello I would like to ask how I can create bash variable in makefile.
Below code does work but variable "targets" keeps being empty. How I can actually create "targets" and "current_target" variables in makefile?. Problem is that I have to create this variables from actual bash commands.
SHELL=/bin/bash
...
MAIN_APPS = 01_prep 02_prep 03_prep 04_prep 05_prep
foo : .check_targets .check_segment
#for f in $(MAIN_APPS) ; do \
targets=$(expr $(last_target) + 1); \
echo $(targets) + 1; \
curent_target=$(expr "$(echo $(f) | head -c 2) + 0"); \
if [ $(targets) = $(current_target)]; then \
break; \
else \
make $(f); \
fi \
done
output:
make foo last_target="02" segm=KI
+ 1
What I want to do is to make targets from my makefile which actually starts from 01 to 05 if I pass an argument last_target="05"
You mix up between make variables and shell variables. And you did not consider that make expands the recipes before passing them to the shell, reason why you frequently need to use $$ instead of $. Or, for command expansion, `...` instead of $(...). You are also using double quotes where you shouldn't (expr "..."). Finally, you use make in your recipe, which is not a good idea. You should use $(MAKE) (see the How the MAKE Variable Works section of the GNU make manual for the details).
Try the following (not tested) maybe:
SHELL=/bin/bash
...
MAIN_APPS = 01_prep 02_prep 03_prep 04_prep 05_prep
foo : .check_targets .check_segment
#for f in $(MAIN_APPS) ; do \
targets=`expr "$(last_target)" + 1`; \
echo "$$targets + 1"; \
tmp=`echo "$$f" | head -c 2`; \
curent_target=`expr "$$tmp" + 0`; \
if [ "$$targets" = "$$current_target" ]; then \
break; \
else \
$(MAKE) "$$f"; \
fi \
done
But I am almost 100% convinced that you are trying to use make as a kind of scripting language instead of as a sophisticated build system. If I understand well you are trying to rebuild only a subset of your MAIN_APPS by specifying a last target number. You could probably achieve the same with a much more make-ish style:
TARGETS := $(shell printf '%02d_prep\n' $$(seq $(last_target)))
.PHONY: foo
foo: $(TARGETS) .check_targets .check_segment
And that's all, no complex recipe for foo. Nothing at all (except, of course, the rules to build .check_targets, .check_segment and all xx_prep targets, that you do not show).
Explanation: I used the $(shell ...) make function and a small shell script to initialize make variable TARGETS with 01_prep 02_prep ... up to $(last_target)_prep. As noted in the comments this shell script does not even require bash and would work with the default make shell (sh). So, if you do not have other good reasons to use bash, get rid of the SHELL=/bin/bash line and your Makefile will be a bit more portable.
Then, I declared foo as phony because you probably don't have a file named foo and, in case you have one, you probably want make to build foo anyway.
Finally, I declared $(TARGETS), .check_targets, and .check_segment as prerequisites of foo. If you ask make to build foo and any of these prerequisites is out-of-date, make will build it using the rules you declared for it.
This is far more make-ish because it clearly tells make what depends on what instead of hiding it in a recipe. And make needs this to do its job correctly, which consist in comparing last modification dates of files to decide if something must be rebuilt or not. It also has extra benefits like, for instance, exploiting the parallelism of your computer to build several xx_prep in parallel if it is possible.

Make command on Kubuntu device

I have to compile a source code to get the executables. However, the make command fails to compile due to the presence of a parantheses with the following error message:
sh: 4: Syntax error: "(" unexpected (expecting ")")
Makefile: 36: recipe for target 'dynamic' failed
make[1]: [dynamic] Error 2
I visited the Makefile which I attach to this post:
# get PETSC_DIR, PETSC_ARCH and MPIHOME from NEMO 5 build system
#LIBMESH_VERSION = 0.8.0
include ../../make.inc
#all: libmesh/configure static dynamic
all: libmesh/configure dynamic
# <ss 12/09/10> static stuff is only needed on jaguar
libmesh/configure:
#echo "Extracting libmesh-$(LIBMESH_VERSION).tar.gz..."
tar zxf libmesh-$(LIBMESH_VERSION).tar.gz
# <ss 17.7.2010> PETSc now is mandatory for libmesh - however, libmesh takes MPI configuration from petsc configuration files in that case.
# libmesh searches for $PETSC_DIR/include/petsc.h and needs $PETSC_ARCH to be set
# On nanohub, things got messed up and OpenMIP libraries linked to executables. to prevent this, I had to disable VTK within libmesh.
# <ss 13.8.2010> disabled tetgen because libtetgen.a seems to contain an int main() which makes static linking impossible.
# Note: the 'make clean' before 'make all' for the contributions is mandatory, otherwise shared LASPACK will not compile.
static: libmesh/configure
#echo "###########################################"
#echo "# #"
#echo "# Configuring Libmesh (STATIC libraries) #"
#echo "# #"
#echo "###########################################"
(export libmesh_CXXFLAGS=$(libmesh_CXXFLAGS) ; \
export libmesh_INCLUDE=$(libmesh_INCLUDE); \
export SLEPC_DIR=$(SLEPC_DIR); \
cd libmesh; ./configure PETSC_DIR=$(PETSC_REAL_BUILD) MPIHOME=$(MPIHOME) PETSC_ARCH=$(PETSC_REAL_ARCH) \
F77="$(MPIF77)" CC="$(MPICC)" GCC="$(GCC)" CXX="$(MPICXX)" --enable-vtk --with-vtk-include=$(VTKINC_PATH) \
--with-vtk-lib=$(VTKLIB_PATH) --disable-tetgen --disable-tecplot \
--disable-nemesis --disable-shared --enable-parmesh --enable-amr; \
make clean; make; \
cd contrib; make clean; make all)
dynamic: libmesh/configure
#echo "###########################################"
#echo "# #"
#echo "# Configuring Libmesh (DYNAMIC libraries) #"
#echo "# #"
#echo "###########################################"
(export libmesh_CXXFLAGS=$(libmesh_CXXFLAGS); \
export libmesh_CPPFLAGS=$(libmesh_CPPFLAGS); \
export libmesh_INCLUDE=$(libmesh_INCLUDE); \
export METHODS=(opt,dbg);\
export SLEPC_DIR=$(SLEPC_DIR)/build-real; \
cd libmesh; ./configure PETSC_DIR=$(PETSC_REAL_BUILD) MPIHOME=$(MPIHOME) PETSC_ARCH=$(PETSC_REAL_ARCH) \
F77="$(MPIF77)" CC="$(MPICC)" GCC="$(GCC)" CXX="$(MPICXX)" --enable-vtk --with-vtk-include=$(VTKINC_PATH) \
--with-vtk-lib=$(VTKLIB_PATH) --disable-tetgen --enable-triangle --enable-slepc --disable-nemesis --disable-cxx11 --disable-strict-lgpl \
--enable-parmesh --enable-amr --enable-shared=yes --disable-glibcxx-debugging ; \
make clean; make --jobs=4; \
cd contrib; make clean; make all --jobs=4;)
clean:
cd libmesh; make clean
distclean:
rm -rf libmesh
I think the problem is about forcing to use the bash shell as I read from other posts. I did so but it didn't work.
I run it using Kubuntu: KDE version of Ubuntu.
Many thanks in advance for help.
The project's README.md looks like you should have used
../configure --with-methods="opt dbg"
(without parentheses, whitespace separated) and not (apparently) ../configure --with-methods="(opt,dbg)"
Check line 4 of the dynamic target, as the error message states:
export METHODS=(opt,dbg);\
should probably be something else, or the part (opt,dbg) should be in double-quotes:
export METHODS="(opt,dbg)";\

Location replaced while running makefile

Code snippets of makefile:
ERROR_PARSER_YACC = $(SRCDIR)/ermparseyac.y
ERROR_PARSER_LEX = $(SRCDIR)/ermparselex.l
ERM_OBJS = \
$(OBJDIR)/ermparseyac.o \
$(OBJDIR)/ermparselex.o \
$(OBJDIR)/ermclient.o \
$(OBJDIR)/ermcommit.o \
$(OBJDIR)/erminit.o \
$(OBJDIR)/ermlog.o \
$(OBJDIR)/ermmcp.o \
$(OBJDIR)/ermsyslog.o \
$(OBJDIR)/ermparse.o \
$(OBJDIR)/ermreport.o
$(ERM_OBJS): $(SRCDIR)/$(#F:.o=.c)
#echo .... Compiling $(#:.o=.c)
$(IDA_CC) $(SRCDIR)/$(#F:.o=.c) -o $#
The value of SRCDIR is "/home/wholesale/children/dev5/comps/erm/src".
When I run the makefile, I get the following error:
.... Compiling /home/wholesale/children/dev5/comps/erm/obj/ermparselex.c
cc -g -DANSI -DORA817 -DTRACE_ON -DIDA_VERSION='"ISP-RG-V5.10.7GEN2A"' -DNO_MCP -DBUILDING_ERP -I/home/wholesale/children/dev5/comps/erm/include -I/home/wholesale/children/dev5/comps/erm/src -I/home/wholesale/children/dev5/comps/erm/module_test -I/home/wholesale/children/dev5/comps/erm/include -I/home/wholesale/children/dev5/comps/cfm/include -c /home/wholesale/children/dev5/comps/erm/src/ermparselex.c -o /home/wholesale/children/dev5/comps/erm/obj/ermparselex.o
/pf24/wholesale/dvp/comps/erm/src/ermparselex.l:282: error: static declaration of âget_comment_lineâ follows non-static declaration
/pf24/wholesale/dvp/comps/erm/src/ermparselex.l:168: error: previous implicit declaration of âget_comment_lineâ was here
I don't understand how makefile is replacing the location "/home/wholesale/children/dev5/comps/erm/src" to a different location "/pf24/wholesale/dvp/comps/erm/src/" which is not present in the sever.
You seem to be confusing make output with your compiler output. The error messages you showed are not produced by make, but by whatever compiler (probably gcc) you're using.
Note that the assignemt to ERROR_PARSER_LEX is a deffered assignment. The value of SRCDIR is expanded whenever ERROR_PARSER_LEX is used. That might explain why the value of SRCDIR doesn't appear to be what you think it should be.
Edit
The problem doesn't appear to be related to your makefile. Make clearly shows that it's passed /home/wholesale/children/dev5/comps/erm/src/ermparselex.c to the compiler as source file.
The error message which points to a different file probably means that some source file is including something from /pf24.
The -E option of gcc can be quite useful in diagnosing such issues. Replace the -o ... options by it, and it'll output the preprocessed source code to stdout. This should show you which file is including the file in /pf24.

Synchronize shell script execution

A modified version of a shell script converts an audio file from FLAC to MP3 format. The computer has a quad-core CPU. The script is run using:
./flac2mp3.sh $(find flac -type f)
This converts the FLAC files in the flac directory (no spaces in file names) to MP3 files in the mp3 directory (at the same level as flac). If the destination MP3 file already exists, the script skips the file.
The problem is that sometimes two instances of the script check for the existence of the same MP3 file at nearly the same time, resulting in mangled MP3 files.
How would you run the script multiple times (i.e., once per core), without having to specify a different file set on each command-line, and without overwriting work?
Update - Minimal Race Condition
The script uses the following locking mechanism:
# Convert FLAC to MP3 using tags from flac file.
#
if [ ! -e $FLAC.lock ]; then
touch $FLAC.lock
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3"
rm $FLAC.lock
fi;
However, this still leaves a race condition.
The "lockfile" command provides what you're trying to do for shell scripts without the race condition. The command was written by the procmail folks specifically for this sort of purpose and is available on most BSD/Linux systems (as procmail is available for most environments).
Your test becomes something like this:
lockfile -r 3 $FLAC.lock
if test $? -eq 0 ; then
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3"
fi
rm -f $FLAC.lock
Alternatively, you could make lockfile keep retrying indefinitely so you don't need to test the return code, and instead can test for the output file for determining whether to run flac.
If you don't have lockfile and cannot install it (in any of its versions - there are several implementations) a robust and portable atomic mutex is mkdir.
If the directory you attempt to create already exists, mkdir will fail, so you can check for that; when creation succeeds, you have a guarantee that no other cooperating process is in the critical section at the same time as your code.
if mkdir "$FLAC.lockdir"; then
# you now have the exclusive lock
: critical section
: code goes here
rmdir "$FLAC.lockdir"
else
: nothing? to skip this file
# or maybe sleep 1 and loop back and try again
fi
For completeness, maybe also look for flock if you are on a set of platforms where that is reliably made available and need a performant alternative to lockfile.
You could implement locking of FLAC files that it's working on. Something like:
if (not flac locked)
lock flac
do work
else
continue to next flac
Send output to a temporary file with a unique name, then rename the file to the desired name.
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3.$$"
mv "$MP3.$$" "$MP3"
If a race condition leaks through your file locking system every once in a while, the final output will still be the result of one process.
To lock a file process you can create a file with the same name with a .lock extension.
Before starting the encoding check the existence of the .lock file, and optionally make sure the date of the lockfile isn't too old (in case the process dies). If it does not exist, create it before the encoding starts, and remove it after the encoding is complete.
You can also flock the file, but this only really works in c where you are calling flock() and writing to the file then closing and unlocking. For a shell script, you probably are calling another utility to do the writing of the file.
How about writing a Makefile?
ALL_FLAC=$(wildcard *.flac)
ALL_MP3=$(patsubst %.flac, %.mp3, $(ALL_FLAC)
all: $(ALL_MP3)
%.mp3: %.flac
$(FLAC) ...
Then do
$ make -j4 all
In bash it's possible to set noclobber option to avoid file overwriting.
help set | egrep 'noclobber|-C'
Use a tool like FLOM (Free LOck Manager) and simply serialize your command as below:
flom -- flac ....

How do I create a directory in a makefile

I'm using Visual Studio 2005 nmake, and I have a test makefile like this:
sometarget:
-mkdir c:\testdir
I want to always create the directory, without having to specify 'sometarget'. For example, I can do this:
!if [if not exist c:\testdir\$(null) mkdir c:\testdir]
!endif
But that requires two lines, where I really only want to do the "-mkdir c:\testdir". If I just replace it with "-mkdir c:\testdir" I get an error from nmake - "fatal error U1034: syntax error : separator missing".
How can I always execute the mkdir, without messing about with !if [] stuff?
I think this will work:
-# if NOT EXIST "dir" mkdir "dir"
Make always wants to do things based on targets. It's not a general scripting tool. It looks at the targets and checks to see if they exist. If the target does not exist it executes the commands for that target.
The usual way to do this is to have a dummy target that is never going to be generated by the make scripts, so every time make runs it has to execute the relevant commands.
Or, you could add the command to a batch file that then calls your make file.
I'm not sure if there is an equivalent in Windows with nmake, but I managed to create a directory without using targets on Linux. I used the make function "shell". For example:
# Find where we are
TOPDIR := $(shell pwd)
# Define destination directory
ROOTFS := $(TOPDIR)/rootfs
# Make sure destination directory exists before invoking any tags
$(shell [ -d "$(ROOTFS)" ] || mkdir -p $(ROOTFS))
all:
#if [ -d "$(ROOTFS)" ]; then echo "Cool!"; else echo "Darn!"; fi
I hope Windows has the equivalent.
$(DIRNAME):
#[ -d $# ] || mkdir -p $#
Try using this:
-mkdir -p c:\testdir

Resources