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))) \ )