Makefile question in OpenWRT build system - makefile

The following code is taken from OpenWRT project. Can someone give an abstract description? Thanks in advance!
#
# Copyright (C) 2007 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
SUBTARGETS:=clean download prepare compile install update refresh prereq dist distcheck
subtarget-default = $(filter-out ., \
$(if $($(1)/builddirs-$(2)),$($(1)/builddirs-$(2)), \
$(if $($(1)/builddirs-default),$($(1)/builddirs-default), \
$($(1)/builddirs))))
define subtarget
$(call warn_eval,$(1),t,T,$(1)/$(2): $($(1)/) $(foreach bd,$(call subtarget-default,$(1),$(2)),$(1)/$(bd)/$(2)))
endef
lastdir=$(word $(words $(subst /, ,$(1))),$(subst /, ,$(1)))
diralias=$(if $(findstring $(1),$(call lastdir,$(1))),,$(call lastdir,$(1)))
# Parameters: <subdir>
define subdir
$(call warn,$(1),d,D $(1))
$(foreach bd,$($(1)/builddirs),
$(call warn,$(1),d,BD $(1)/$(bd))
$(foreach target,$(SUBTARGETS),
$(foreach btype,$(buildtypes-$(bd)),
$(call warn_eval,$(1)/$(bd),t,T,$(1)/$(bd)/$(btype)/$(target): $(if $(QUILT),,$($(1)/$(bd)/$(btype)/$(target)) $(call $(1)//$(btype)/$(target),$(1)/$(bd)/$(btype))))
+$$(SUBMAKE) -C $(1)/$(bd) $(btype)-$(target) $(if $(findstring $(bd),$($(1)/builddirs-ignore-$(btype)-$(target))), || $(call MESSAGE, ERROR: $(1)/$(bd) [$(btype)] failed to build.))
$$(if $(call debug,$(1)/$(bd),v),,.SILENT: $(1)/$(bd)/$(btype)/$(target))
$(if $(call diralias,$(bd)),$(call warn_eval,$(1)/$(bd),l,T,$(1)/$(call diralias,$(bd))/$(btype)/$(target): $(1)/$(bd)/$(btype)/$(target)))
)
$(call warn_eval,$(1)/$(bd),t,T,$(1)/$(bd)/$(target): $(if $(QUILT),,$($(1)/$(bd)/$(target)) $(call $(1)//$(target),$(1)/$(bd))))
$(if $(BUILD_LOG),#mkdir -p $(BUILD_LOG_DIR)/$(1)/$(bd))
$(foreach variant,$(if $(BUILD_VARIANT),$(BUILD_VARIANT),$(if $($(1)/$(bd)/variants),$($(1)/$(bd)/variants),__default)),
+$(if $(BUILD_LOG),set -o pipefail;) $$(SUBMAKE) -C $(1)/$(bd) $(target) BUILD_VARIANT="$(filter-out __default,$(variant))" $(if $(BUILD_LOG),SILENT= 2>&1 | tee $(BUILD_LOG_DIR)/$(1)/$(bd)/$(target).txt) $(if $(findstring $(bd),$($(1)/builddirs-ignore-$(target))), || $(call MESSAGE, ERROR: $(1)/$(bd) failed to build$(if $(filter-out __default,$(variant)), (build variant: $(variant))).))
)
$$(if $(call debug,$(1)/$(bd),v),,.SILENT: $(1)/$(bd)/$(target))
# legacy targets
$(call warn_eval,$(1)/$(bd),l,T,$(1)/$(bd)-$(target): $(1)/$(bd)/$(target))
# aliases
$(if $(call diralias,$(bd)),$(call warn_eval,$(1)/$(bd),l,T,$(1)/$(call diralias,$(bd))/$(target): $(1)/$(bd)/$(target)))
)
)
$(foreach target,$(SUBTARGETS),$(call subtarget,$(1),$(target)))
endef
# Parameters: <subdir> <name> <target> <depends> <config options> <stampfile location>
define stampfile
$(1)/stamp-$(3):=$(if $(6),$(6),$(STAGING_DIR))/stamp/.$(2)_$(3)$(if $(5),_$(call confvar,$(5)))
$$($(1)/stamp-$(3)): $(TMP_DIR)/.build $(4)
#+$(SCRIPT_DIR)/timestamp.pl -n $$($(1)/stamp-$(3)) $(1) $(4) || \
$(MAKE) $$($(1)/flags-$(3)) $(1)/$(3)
#mkdir -p $$$$(dirname $$($(1)/stamp-$(3)))
#touch $$($(1)/stamp-$(3))
$$(if $(call debug,$(1),v),,.SILENT: $$($(1)/stamp-$(3)))
.PRECIOUS: $$($(1)/stamp-$(3)) # work around a make bug
$(1)//clean:=$(1)/stamp-$(3)/clean
$(1)/stamp-$(3)/clean: FORCE
#rm -f $$($(1)/stamp-$(3))
endef

The subdir template generates the standard make targets for a subdirectory.
It is called with the directory name as first argument, e.g. in package/Makefile it's 'package'
it then treats the variable package/builddirs as the list of subdirectories with valid build targets, which are contained in the SUBTARGETS variable.
For running the 'compile' target of a package 'foo', it allows you to run 'make package/foo/compile' which will recursively invoke make with the right environment variables in order to build the subdirectory.
This template also has support for some optional features that can be enabled through environment variables, e.g. for logging the output to a file, ignoring dependencies, etc.
It also supports selective debugging output.
The stampfile template is simply a small makefile target wrapper for speeding up builds by keeping a recursively timestamp-checked stampfile around it

Related

What's the purpose of that use 'dir &# ' as order-only-prerequisites?

Below code is part of Makefile,i confuse what the purpose of use $$$$(dir $$$$#) as order-only-prerequisites in cc_template function
.SECONDEXPANSION:
# get .o obj files: (#files[, packet])
toobj = $(addprefix $(OBJDIR)$(SLASH)$(if $(2),$(2)$(SLASH)),\
$(addsuffix .o,$(basename $(1))))
# get .d dependency files: (#files[, packet])
todep = $(patsubst %.o,%.d,$(call toobj,$(1),$(2)))
# cc compile template, generate rule for dep, obj: (file, cc[, flags, dir])
define cc_template
$$(call todep,$(1),$(4)): $(1) | $$$$(dir $$$$#)
#$(2) -I$$(dir $(1)) $(3) -MM $$< -MT "$$(patsubst %.d,%.o,$$#) $$#"> $$#
$$(call toobj,$(1),$(4)): $(1) | $$$$(dir $$$$#)
#echo + cc $$<
$(V)$(2) -I$$(dir $(1)) $(3) -c $$< -o $$#
ALLOBJS += $$(call toobj,$(1),$(4))
endef
The whole Makefile is from https://github.com/chyyuu/ucore_os_lab/blob/master/labcodes/lab1/tools/function.mk
Since you didn't directly ask about the quoting I won't go through it, except to say that after all is said and done what this will do is make the target's directory into an order-only prerequisite.
So, if your target is my/foo/bar.o then my/foo will be an order-only prerequisite of that target.
This is done to ensure that the target directory exists before invoking the rule that creates an object file in it (the compiler won't create output directories for you: if they don't exist it will just fail).
Elsewhere in your makefile you should find a rule that creates directories:
<sometargets>:
mkdir -p $#
.PHONY: <sometargets>

"variable" target name in makefile

how good/bad practice is it to have "nonconstant" targets in a makefile?
The company I work for produces embedded equipment, and I'm a firmware engineer.
The coding rules of the company I work for require that files produced by a build must have a name tagged with the version and also with a hash of information from a git repository (for test and production department needs).
An additional constraint is that a build is produced with a single command.
That's why I'm faced with makefiles every day whose targets have names that can change from build to build.
I wonder if these are common problems or not.I wonder if the example I wrote is a good practice to solve it:
# This is just an example to (hopefully) help to understand.
define populate_variable_with_remote_file_content
$(if $(findstring $(origin $(1)),undefined), \
$(eval $(1) = $(shell git archive master --remote=git#gitserver:project.git $(2) | tar -x --to-stdout)) \
)
endef
.PHONY: clean populate_TAG
all: populate_TAG
$(eval TARGET = dummy_$(TAG))
$(eval export TAG TARGET)
$(MAKE) -f $(firstword $(MAKEFILE_LIST)) $(TARGET)
$(TARGET):
echo hallo > $#
populate_TAG:
$(eval $(call populate_variable_with_remote_file_content,TAG,somefile))
clean:
rm dummy_*
I wonder if there are other (better) ways to solve this.

Openwrt Makefile with custom compile definition does not get executed

I'm trying to get a custom compile definition to work to seperete "make compile" from "make install" but the custom definition Build/compile never gets executed.
define Build/compile
echo -e "\e[1;34m \nBuild/compile $(PKG_NAME)\n $<\e[0m" \
$(MAKE) $(MAKE_FLAGS) -C $(PKG_BUILD_DIR) \
DESTDIR="$(PKG_INSTALL_DIR)"
endef
this does not work when executed like: make -j1 V=s package/network/nodejs/node/compile
but the prepare step works:
define Build/Prepare
echo -e "\e[1;34m \nBuild/Prepare $(PKG_NAME)\n $<\e[0m"
endef
when executed with: make -j1 V=s package/network/nodejs/node/prepare
So please could you help to find out what goes wrong with the following script:
#
# Copyright (C) 2007-2011 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=nodejs
PKG_VERSION:=0.12.7
PKG_RELEASE:=0
PKG_SOURCE:=node-v$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://nodejs.org/dist/v$(PKG_VERSION)/
PKG_MD5SUM:=5523ec4347d7fe6b0f6dda1d1c7799d5
PKG_BUILD_DEPENDS:=nodejs/host
HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/node-v$(PKG_VERSION)
PKG_BUILD_DIR:=$(BUILD_DIR)/node-v$(PKG_VERSION)
#PKG_INSTALL:=1
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/host-build.mk
include $(INCLUDE_DIR)/package.mk
define Package/nodejs
SUBMENU:=Node.js
SECTION:=net
CATEGORY:=Network
TITLE:=Node.js Evented I/O for V8 JavaScript
URL:=http://nodejs.org
MAINTAINER:=Xin Ouyang <xinpascal#gmail.com>
DEPENDS:=#armeb||#arm||#i386 +libstdcpp +libpthread +librt +libopenssl +uclibcxx
endef
define Package/nodejs/description
Node.js is a platform built on Chrome's JavaScript runtime for easily
building fast, scalable network applications. Node.js uses an event-driven,
non-blocking I/O model that makes it lightweight and efficient, perfect
for data-intensive real-time applications that run across distributed
devices.
endef
define Package/nodejs-npm
SUBMENU:=Node.js
SECTION:=net
CATEGORY:=Network
TITLE:=Node Package Manager
URL:=https://npmjs.org
MAINTAINER:=Xin Ouyang <xinpascal#gmail.com>
DEPENDS:=#armeb||#arm||#i386 +libstdcpp +libpthread +librt +libopenssl +uclibcxx
endef
define Package/nodejs-npm/description
npm is the package manager for the Node JavaScript platform. It puts
modules in place so that node can find them, and manages dependency
conflicts intelligently.
endef
#We need to override all args becouse they are not compatible with the build script
CONFIGURE_ARGS:=
HOST_CONFIGURE_ARGS:=
HOST_CONFIGURE_CMD:=$(HOST_CONFIGURE_VARS) ./configure --without-snapshot ;
CONFIGURE_ARGS:= --without-snapshot
#HOST_CONFIGURE_ARGS:=
HOST_MAKE_FLAGS +=
BUILDTYPE=Release i18nsupport=off
define Build/Prepare
echo -e "\e[1;34m \nBuild/Prepare $(PKG_NAME)\n $<\e[0m"
endef
define Build/nodejs/Compile
echo -e "\e[1;34m \n Build/Compile $(PKG_NAME) \n $<\e[0m"
endef
define Build/compile
echo -e "\e[1;34m \nBuild/compile $(PKG_NAME)\n $<\e[0m" \
$(MAKE) $(MAKE_FLAGS) -C $(PKG_BUILD_DIR) \
DESTDIR="$(PKG_INSTALL_DIR)"
endef
define Package/nodejs/install
echo -e "\e[1;34m \nBuild/install $(PKG_NAME)\n $<\e[0m" \
$(MAKE) $(MAKE_FLAGS) -C $(PKG_BUILD_DIR) install DESTDIR=$(PKG_INSTALL_DIR)
$(INSTALL_DIR) $(1)/usr/bin
$(CP) $(PKG_INSTALL_DIR)/usr/bin/node $(1)/usr/bin/node
endef
define Package/nodejs-npm/install
$(INSTALL_DIR) $(1)/usr/bin
$(CP) $(PKG_INSTALL_DIR)/usr/bin/npm $(1)/usr/bin/npm
$(INSTALL_DIR) $(1)/usr/lib/node_modules
$(CP) -r $(PKG_INSTALL_DIR)/usr/lib/node_modules/npm/ \
$(1)/usr/lib/node_modules
endef
#define Build/InstallDev
# $(INSTALL_DIR) $(1)/usr/share/nodejs-src
# $(CP) $(PKG_BUILD_DIR)/* $(1)/usr/share/nodejs-src
#endef
$(eval $(call HostBuild))
$(eval $(call BuildPackage,nodejs))
$(eval $(call BuildPackage,nodejs-npm))
It should be Build/Compile, not compile (capital C).

Using Qmake in Makefile?

Normally, what I would do is to create two makefiles; one manually and another automatically using qmake. Right now, I'd like to find a way to use qmake inside the makefile that I've created manually.
Here it is:
#
# Copyright (C) 2011 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=cloud
PKG_RELEASE:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/cloud
SECTION:=Cloud
CATEGORY:=cloud
TITLE:=Package
endef
define Package/cloud/description
Cloud Package
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Configure
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
CC="$(TARGET_CC)" \
CFLAGS="$(TARGET_CFLAGS) -Wall" \
LDFLAGS="$(TARGET_LDFLAGS)"
endef
define Package/cloud/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/cloud$(1)/usr/sbin/
endef
$(eval $(call BuildPackage,cloud))
Is it possible?

Could OpenWrt run on barebox?

Could OpenWrt run on barebox
Is there a portable application framework on top of uboot/barebox? So my source code is indepent from the low-level hardware.
Absolutely possible. I've been using barebox as a main bootloader for imx25 SoC. There is no barebox in a public packages though(I've never met it), but you can build your own "bootloader-barebox" package.
Just follow these links:
https://vivekian2.wordpress.com/2007/03/28/building-your-own-package-for-openwrt/
http://prplfoundation.org/wiki/Creating_an_OpenWrt_package_for_a_web_page
I'm not sure about framework, but you probably know that you can create an application. http://www.denx.de/wiki/view/DULG/UBootStandalone
Here is an example of Makefile for barebox:
#
# Copyright (C) 2013 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=barebox
PKG_VERSION:=0.1
PKG_RELEASE:=0
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)
PKG_SOURCE:=$(PKG_NAME).tar.bz2
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=GIT-URL
PKG_SOURCE_VERSION:=93aeafd04365cdd5dcb958cc6982c672163154ee
PKG_SOURCE_SUBDIR:=$(PKG_NAME)
PKG_MD5SUM:=
PKG_TARGETS:=bin
include $(INCLUDE_DIR)/package.mk
define barebox/Default
TITLE:=
CONFIG:=
IMAGE:=
endef
define Package/barebox/template
define Package/barebox-$(1)
SECTION:=boot
CATEGORY:=Boot Loaders
TITLE:=$(2)
DEPENDS:=#TARGET_$(1)
URL:=http://localhost/
DEFAULT:=y if (TARGET_$(1)_Default)
VARIANT:=$(1)
endef
endef
define BuildBareboxPackage
$(eval $(barebox/Default))
$(eval $(barebox/$(1)))
$(call Package/barebox/template,$(1),$(TITLE))
endef
define barebox/imx
TITLE:=Barebox for the imx.
endef
BAREBOXS:=imx
ifdef BUILD_VARIANT
$(eval $(call barebox/$(BUILD_VARIANT)))
BAREBOX_CONFIG:=$(if $(CONFIG),$(CONFIG),$(BUILD_VARIANT))
BAREBOX_IMAGE:=$(if $(IMAGE),$(IMAGE),openwrt-$(BOARD)-$(BUILD_VARIANT)-barebox.bin)
endif
define Build/Prepare
$(call Build/Prepare/Default)
endef
define Build/Configure
$(CP) ./barebox-config $(PKG_BUILD_DIR)/.config
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
CROSS_COMPILE=$(TARGET_CROSS) ARCH=arm
endef
define Package/barebox/install/template
define Package/barebox-$(1)/install
$(CP) $(PKG_BUILD_DIR)/barebox.bin $(BIN_DIR)/$(2)
endef
endef
$(foreach u,$(BAREBOXS), \
$(eval $(call Package/barebox/install/template,$(u),openwrt-$(BOARD)-$(u)-barebox.bin)) \
)
$(foreach u,$(BAREBOXS), \
$(eval $(call BuildBareboxPackage,$(u))) \
$(eval $(call BuildPackage,barebox-$(u))) \
)

Resources