Using makefile file as prerequisite in a rule - c

I am inexperienced with make, and wanted to replicate a build structure provided by some third-party SDK and adapt it to my own compiler and project.
The thing is that I found that some rules are generated using the makefile as prerequisite, something like:
...
$(eval $(1): Makefile | $(dir $(1)).) \
...
or
$(OUTPUT_DIRECTORY)/%.inc: Makefile | $(OUTPUT_DIRECTORY)
$(info Generating $#)
$(NO_ECHO)$(call dump, $(call target_specific, INC_PATHS, $*)) > $#
Originally, their makefile is Capitalized (Makefile) and the one I am working on is lowercase (makefile). Anyway, When I try my current changes, this error appears:
*** No rule to make target 'Makefile', needed by '...'
I supposed that was due to the capitalization, so changed to lowercase in both places and tried again, but this time the error is that the makefile is treated as a C file (This is my guess...)
"makefile", line 1: error #171: expected a declaration
-include makefile.local
^
"makefile", line 67: error #8: missing closing quote
${CG_TOOL_ROOT}/include"
^
"makefile", line 99: error #10: "#" not expected here
.SUFFIXES: # ignore built-in rules
^
"makefile", line 100: error #10: "#" not expected here
%.d: # don't try to make .d files
^
"makefile", line 100: error #8: missing closing quote
%.d: # don't try to make .d files
What could be the issue here? Is there something I am missing?
EDIT 1:
These are the files I am trying to use.
Nordic provides these as part of their SDK for development using arm-gcc for ARM platforms. There is a Makefile per project and there is a Makefile.common included in the main Makefile.
Makefile
Makefile.common
On the other side, I am trying to understand and replicate the same but for another proprietary compiler with different options and syntax (TI's cl430 for MSP430 platforms). From the original Makefile.common I removed some references to the gnu-arm suite and replace it with the proper compiling tools. In the makefile I also tried to replicate the same structure of the original but using my sources and options.
makefile
makefile.common
Just to make it clear, originals are capitalized, mine are lowercase.
EDIT 2:
After running make --debug --print-data-base I found this:
The error appears in the first attempt to build a file:
Updating goal targets....
File 'default' does not exist.
File 'test_project' does not exist.
File '_build/test_project.out' does not exist.
File '_build/test_project/<SOURCE_FILE>.c.o' does not exist.
Must remake target '_build/test_project/<SOURCE_FILE>.c.o'.
Building file: "makefile"
Invoking: MSP430 Compiler
"cl430" -vmspx --use_hw_mpy=F5 <... a lot of options ...> --obj_directory="./_build" "makefile"
"makefile", line 1: error #171: expected a declaration
-include makefile.local
^
[ ... more errors ...]
However, from the debug and DB information, I found that the source file rule indeed requires makefile, and that makefile is not a target, but somehow it is trying to build it:
# Not a target:
makefile:
# Implicit rule search has been done.
# Last modified 2020-02-25 11:43:33.609423171
# File has been updated.
# Successfully updated.
_build/test_project/<SOURCE_FILE>.c.o: makefile | _build/test_project/.
# Implicit rule search has been done.
# Implicit/static pattern stem: '_build/test_project/<SOURCE_FILE>'
# Modification time never checked.
# File has been updated.
# Failed to be updated.
# automatic
# # := _build/test_project/<SOURCE_FILE>.c.o
# automatic
# % :=
# automatic
# * := _build/test_project/<SOURCE_FILE>
# automatic
# + := makefile
# automatic
# | := _build/test_project/.
# automatic
# < := makefile
# automatic
# ^ := makefile
# automatic
# ? := makefile
# variable set hash-table stats:
# Load=8/32=25%, Rehash=0, Collisions=1/30=3%
# recipe to execute (from 'makefile.common', line 192):
#echo 'Building file: "$<"'
#echo 'Invoking: MSP430 Compiler'
"${CG_TOOL_ROOT}/bin/cl430" -vmspx --use_hw_mpy=F5 <... a lot of options ...> "$(shell echo $<)"
#echo 'Finished building: "$<"'
#echo ' '

That dependency on Makefile is to make sure that it rebuilds when Makefile has been changed. For example, if you change CFLAGS in Makefile or a rule to compile or link, this dependency triggers a rebuild (provided object files depend on Makefile, as they should). Without dependency on Makefile those changes won't cause a rebuild.
The error messages in the form of "makefile", line 1: error #171: expected a declaration suggest that makefile is passed as a source file to a C compiler that produces the error message.
The rules most likely do $(filter-out Makefile,$^). You need to replace all occurrences of Makefile to makefile.
*** No rule to make target 'Makefile', needed by '...' means that Makefile is still a prerequisite of some targets. You can find what those targets are by passing --debug --print-data-base command line options to make.

Related

OpenWrt Makefile include package.mk error

I'm such a beginner on OpenWrt and Makefiles, trying to demonstrate "Helloworld" example of creating a package but at the package feed update step, from command ./scripts/feeds update mypackages I get this error
Updating feed 'mypackages' from '/home/onur/Desktop/OpenWRT/openwrt/mypackages' ...
Create index file './feeds/mypackages.index'
/home/onur/Desktop/OpenWRT/openwrt/feeds/mypackages.tmp/info/.files-packageinfo.mk:1: *** target pattern contains no '%'. Stop.
I have src-link mypackages /home/onur/Desktop/OpenWRT/openwrt/mypackages in my feeds.conf, "helloworld" C program compiled on /openwrt/helloworld directory and below is my Makefile:
include $(TOPDIR)/rules.mk
# Name, version and release number
# The name and version of your package are used to define the variable to point to the build directory of your package: $(PKG_BUILD_DIR)
PKG_NAME:=helloworld
PKG_VERSION:=1.0
PKG_RELEASE:=1
# Source settings (i.e. where to find the source codes)
# This is a custom variable, used below
SOURCE_DIR:=/home/onur/Desktop/OpenWRT/openwrt/helloworld
include $(INCLUDE_DIR)/package.mk
# Package definition; instructs on how and where our package will appear in the overall configuration menu ('make menuconfig')
define Package/helloworld
SECTION:=examples
CATEGORY:=Examples
TITLE:=Hello, World!
endef
# Package description; a more verbose description on what our package does
define Package/helloworld/description
A simple "Hello, world!" -application.
endef
# Package preparation instructions; create the build directory and copy the source code.
# The last command is necessary to ensure our preparation instructions remain compatible with the patching system.
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
cp $(SOURCE_DIR)/* $(PKG_BUILD_DIR)
$(Build/Patch)
endef
# Package build instructions; invoke the target-specific compiler to first compile the source file, and then to link the file into the final executable
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
CXX="$(TARGET_CROSS)g++"
endef
# Package install instructions; create a directory inside the package to hold our executable, and then copy the executable we built previously into the folder
define Package/helloworld/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/usr/bin
endef
# This command is always the last, it uses the definitions and variables we give above in order to get the job done
$(eval $(call BuildPackage,helloworld))
I know I may have mistake on cross-compile part but I don't think that's the issue that I'm having right now.
When I try to make this Makefile, I get that error.
Makefile:13: /package.mk: No such file or directory
make: *** No rule to make target '/package.mk'. Stop.
I can't find any problem like this anywhere. Why it can't even find "package.mk" file.
My directory structure is like, Top directory is Desktop/OpenWrt/openwrt and this Makefile is in Desktop/OpenWrt/openwrt/mypackage folder. I'm on Ubuntu 20.04
I found solution to my question on OpenWrt Forum. Here is the link of thread

the way to put my own package and compile openwrt

I wrote my own openwrt package for my script and the compilation stage I put it in the package file as this path openwrt / feeds / package / is that the path is correct or not?
or if I have is for the compilation error:
make[1]: *** No rule to make target `package/test/compile'. Stop.
make: *** [package/test/compile] Error 2
THis my Makefile:
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=test
PKG_VERSION:=1.0
PKG_RELEASE:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
DEPENDS:= +nmap +python
include $(INCLUDE_DIR)/package.mk
define Package/test
SECTION:=secure
CATEGORY:=Monitoring
TITLE:=test
define Package/test/description
test tis is my first package
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/test/install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/test $(1)/bin/
endef
$(eval $(call BuildPackage,test))
I need help please.
thanks.
You don't really have to put your source code anywhere in the /openwrt/ folder. It can be placed, let's say, in /Documents/[name] folder. However it is important that you put your OpenWRT-specific Makefile in the /openwrt/ tree. I am not sure if putting your Makefile in /openwrt/feeds/package is correct but I put my Makefiles in /openwrt/package/[name] folder which works fine. Your source code will be automatically copied by the toolchain to the same folder anyway.
Note: if you place your source code somewhere on your system (for example, in the Documents folder) you have to specify the path to it in your Makefile as follows: PKG_SOURCE_URL:=file://$(TOPDIR)/../Documents/[name]
Your make[1] errors are basically telling you that the toolchain could not find the Makefile. Try putting Makefile in /openwrt/package/[name].

Issues with makefile producing fatal error "Don't know how to make target" using C source files

I am having an issue with this makefile giving the fatal error: "Don't know how to make target calc.o". The naming is correct along with being in the working directory, and the other issue is that when I switch the order of the object files for default target file it will say it does not know how to make that target either, so the order does not seem to change anything or be one specific file. I am running the make command on a sun sparc unix server as well. The makefile is pasted below:
#The following rule tells make about possible suffixes
#(extensions) of file names.
.SUFFIXES: .c .o
#The following definition of CC ensures that
#gcc will be used to compile the C source files.
CC = gcc
#The following definition of CFLAGS ensures that
#the debugger can be used with the executable file (p1)
#created by running make.
CFLAGS = -g
#The following rule tells make how a ".o" file should
#be created from the corresponding ".c" file.
#Note that the "-c" option must be used here since we are
#compiling source files separately. (Note that the line
#following the ".c.o:" line begins with the "tab" character.)
.c.o:
$(CC) $(CFLAGS) -c $<
#Dependency rule for the default target and how the
#default target is to be created. (Note that the line
#following the dependency rule begins with the "tab"
#character.)
p2: main.o textToBin.o binToText.o calc.o
gcc main.o textToBin.o binToText.o calc.o -o p2
#Dependency rules for other targets. (We don't need to
#specify how these targets are created since we have already
#given a general rule for creating a ".o" file from the
#corresponding ".c" file.)
#NO HEADER FILES
#Target for removing unnecessary files.
clean:
rm -f *.o core

Automake, GNU make, check, and (ignored) pattern rules

I have the following Makefile.am which is supposed to create foo.hdb and foo.cdb from foo.h (via the Python script):
TESTS = check_foo
check_PROGRAMS = check_foo
check_foo_SOURCES = check_foo.c $(top_builddir)/src/isti.h \
foo.cdb foo.h foo.hdb
check_foo_CFLAGS = #CHECK_CFLAGS# $(all_includes) -I../../clib/src/
check_foo_LDADD = $(top_builddir)/src/libcorm.la #CHECK_LIBS# -lsqlite3
%.hdb %.cdb: %.h
PYTHONPATH=$(top_builddir)/cgen/src python $(top_builddir)/cgen/src/isti/cgen/run.py $<
clean-local:
rm -f *.hdb *.cdb
However, although make foo.hdb and make foo.cdb work (call the Python code and generates the foo.hdb and foo.cdb files from foo.h), make clean check (or the two separately) does not (missing foo.hdb - no such file) - the pattern rule is not called to generate foo.hdb from foo.h.
In other words: the pattern rule is not being called for the files listed in check_foo_SOURCES.
How can I make this work? The rest of the autotools infrastructure is working fine. From looking at the Makefile I suspect the issue is with how autotools expands the check sources.
This is all on Linux with Gnu make. Here is the Makefile.
[Updated slightly to reflect the help from MadScientist].
Later update
The following Makefile (just make, not autotools) works fine, so the issue seems to be related to autotools and check support.
all: check_foo
CFLAGS=-I../../clib/src
LDFLAGS=-L../../clib/src/.libs
check_foo: check_foo.c foo.h corm_foo.h corm_foo.c
gcc $(CFLAGS) $(LDFLAGS) $^ -o $# -lcorm -lsqlite3
corm_%.h corm_%.c: %.h
PYTHONPATH=../../cgen/src python ../../cgen/src/isti/cgen/run.py $<
clean:
rm -f corm_*.h corm_*.c
rm -f *.o
(Note that I've switched from xxx.hdb to corm_xxx.h, etc, so that file extensions remain OK).
More Details
Since it seems to be related to the CHECK macros, this is configure.ac:
AC_INIT([corm], [0.1], [a.cooke#isti.com])
AC_CONFIG_MACRO_DIR([m4])
PKG_CHECK_MODULES([CHECK], [check >= 0.9.4])
AM_INIT_AUTOMAKE([-Wall foreign -Werror])
AC_PROG_CC_C99
AM_PROG_CC_C_O
LT_INIT
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile clib/Makefile clib/src/Makefile clib/tests/Makefile clib/docs/Makefile cgen/Makefile cgen/docs/Makefile example/Makefile example/src/Makefile])
AC_CHECK_PROGS([DOXYGEN], [doxygen], AC_MSG_WARN([Doxygen not found - continuing without Doxygen support]))
AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([clib/docs/Doxyfile cgen/docs/Doxyfile])])
SOLUTION
OK, so summarizing the various things below, there were two important issues (once I had fixed file extensions - see the "plain" makefile and fceller's answer), either one of which was sufficient to make things work:
(The handling of) Header files is complicated. Because of auto-dependencies, programatically generated header files break things. The solution is to use BUILT_SOURCES
But (the handling of) .c files is not complicated. So putting the corm_foo.c in front of check_foo.c would trigger the generation of that file. Since that also generates corm_foo.h, everything works (because check_foo.c now can include corm_foo.h).
Also, fceller has some good general points about tidy makefiles and explains why the "plain" makefile works.
The line
%.cdb: %.hdb
does not do anything. Check the GNU make manual and you'll see that a pattern rule without a command line is used to DELETE a previously defined rule with that same pattern. Since there's no previous rule, this is essentially a no-op.
If you have a command that creates TWO output files with ONE invocation of a rule, then you need to put both patterns in the same rule, like this:
%.cdb %.hdb: %.h
PYTHONPATH=$(top_builddir)/cgen/src python $(top_builddir)/cgen/src/isti/cgen/run.py $<
This will tell GNU make that both targets are generated from one invocation of the rule. BE AWARE! This syntax only has this behavior for pattern rules. Explicit rules with multiple targets do something entirely different (confusingly enough).
As for the make clean behavior, I'm not sure. The makefile generated by automake is too complex for me to just read it; it would require some debugging (run it and trace what happens). However, I suspect that the rules there are not designed properly to allow a clean target and a build target to both be run in the same invocation of make. Run the two commands separately and see if that works better:
make clean
make check
You need to tell automake that foo.hdb is a source file that is to be constructed. Add the following to Makefile.am:
BUILT_SOURCES = foo.hdb
First of all: you do not need to include the "*.h" in *_SOURCES. The automake will generated code to generate the dependencies. From the manual: Header files listed in a _SOURCES definition will be included in the distribution but otherwise ignored
The change you made in the plain Makefile ("Note that I've switched from xxx.hdb to corm_xxx.h, etc, so that file extensions remain OK") is essential. The automake FILTERS the *_SOURCES list using the filename extension in order to see what to call (CC, CXX, F77).
The following Makefile.am will work:
TEST = check_foo
check_PROGRAMS = check_foo
check_foo_SOURCES = check_foo.c foo.db.c
check_foo_CFLAGS =
check_foo_LDADD =
%.db.c %.db.h: %.h
echo "int i = 1;" > foo.db.c
echo "int j;" > foo.db.h
clean-local:
rm -f *.db.h *.db.c
Let me try to add an indirect answer/discussion to the existing direct ones.
I recently moved away from make for the same kind of reasons you experienced: it is extremely powerful but sometimes a bit difficult to debug when things do not go as expected.
I recently discovered pydoit which is very promising as a debuggable replacement build tool for make. Since the notion of "pattern rules" was not present in it, I proposed an independent package to do the job: fprules.
This is how you would perform the same task that you mention in your post, with doit and fprules:
from fprules import file_pattern
# all: check_foo
DOIT_CONFIG = {'default_tasks': ['check_foo']}
CFLAGS = '-I../../clib/src'
LDFLAGS = '-L../../clib/src/.libs'
# check_foo: check_foo.c foo.h corm_foo.h corm_foo.c
# gcc $(CFLAGS) $(LDFLAGS) $^ -o $# -lcorm -lsqlite3
def task_check_foo():
"""
Compiles the `check_foo` executable
"""
src_files = ('check_foo.c', 'foo.h', 'corm_foo.h', 'corm_foo.c')
dst_file = 'check_foo'
return {
'file_dep': src_files,
'actions': ["gcc %s %s %s -o %s -lcorm -lsqlite3" % (CFLAGS, LDFLAGS, ' '.join(src_files), dst_file)],
'verbosity': 2,
'targets': [dst_file],
'clean': True
}
# corm_%.h corm_%.c: %.h
# PYTHONPATH=../../cgen/src python ../../cgen/src/isti/cgen/run.py $<
def task_gen_corm():
"""
Generates files `corm_%.h` and `corm_%.c`
for each header file `%.h`.
"""
for data in file_pattern('./*.h', dict(h_file='./corm_%.h', c_file='./corm_%.c')):
yield {
'name': data.name,
'file_dep': [data.src_path],
'actions': ["PYTHONPATH=../../cgen/src python ../../cgen/src/isti/cgen/run.py %s" % data.src_path],
'verbosity': 2,
'targets': [data.h_file, data.c_file],
'clean': True
}
# clean:
# rm -f corm_*.h corm_*.c
# rm -f *.o
# No need to create tasks for this:
# with 'clean': True, `doit clean` will clean all target files
Then simply run doit in the folder.
Do not hesitate to provide feedback on the projects pages if needed: for example multiline commands are not supported, you can vote for them if you too feel that they are missing: https://github.com/pydoit/doit/issues/314

Mingw and make variables

I'm trying to compile an open source project on windows under mingw/msys.
The makefile contains (among others) this line
#${MAKE} --no-print-directory -C . -f physfs.make
physfs.make contains (among others) these lines:
ifndef CC
CC = gcc
endif
when I ran make I get the following error:
Creating obj/Debug/physfs
physfs.c
make[1]: cc: Command not found
make[1]: *** [obj/Debug/physfs/physfs.o] Error 127
make: *** [physfs] Error 2
If I comment the ifndef / endif pair leaving CC = gcc intact, the build works. If instead of make I issue this command:
make -e CC=gcc
the build works as well. But when I run the following command in msys:
echo $CC
nothing is displayed.
I think there is something basic about how environment variables work in MSYS and make that I don't understand.
Could please some help me troubleshoot this issue, so I can understand why simple 'make' command complains and why the ifndef block doesn't function as I expect it to function.
CC is one of several implicit variables automatically defined in a make session, so the line ifndef CC should never evaluate to true.
This explains why you see nothing on the command line for echo $CC. The MSYS environment has no concept of CC.
If you want to see the value of variables from within a make session, you can always use the info function:
$(info $(CC))
This will echo the value of the CC variable to the console at the point when that line in the makefile is evaluated.

Resources