How to change variable values when a target is called - makefile

I have following things in my Makefile(GNU)
DLIB = $(DLIB_STATIC)
DLIBFLAGS = $(DLIB_STATIC)
DLIB_BUILDS = $(DLIB_STATIC) LIBDDUMMY
# DLIB = $(DLIB_SHARED)
# DLIBFLAGS = -Llib -lD
# DLIB_BUILDS = $(DLIB_SHARED)
all: BUILDALL TB
tgt2: BUILDALL TB
TB: $(DLIB_BUILDS)
I need to modify values of DLIB, DLIBFLAGS & DLIB_BUILDS as follows
DLIB = $(DLIB_SHARED)
DLIBFLAGS = -Llib -lD
DLIB_BUILDS = $(DLIB_SHARED)
when tgt2 is called.
I tried following
TEMP:
DLIB = $(DLIB_SHARED)
DLIBFLAGS = -Llib -lD
DLIB_BUILDS = $(DLIB_SHARED)
tgt2: TEMP BUILDALL
But it not working, how can I do that ?

GNU make has notion about target-specific variable values. Just place variable's assignment in place of target's prerequisites:
tgt2: DLIB = $(DLIB_SHARED)
tgt2: DLIBFLAGS = -Llib -lD
tgt2: DLIB_BUILDS = $(DLIB_SHARED)
tgt2: BUILDALL
That way, if BUILDALL target is built via tgt2, it will use special set of variable's values.

Related

Makefile variable printing empty despite definition structure

I am working on a C++ library where I am following the structure below:
ROOTDIR = ~/path/to/proj
BLDDIR = $(ROOTDIR)/build
INCDIR = $(ROOTDIR)/include
SRCDIR = $(ROOTDIR)/src
LIBSRCDIR = $(SRCDIR)/lib
TESTSRCDIR = $(SRCDIR)/test
OBJDIR = $(ROOTDIR)/obj
LIBOBJDIR = $(OBJDIR)/lib
TESTOBJDIR = $(OBJDIR)/test
LIBDIR = $(ROOTDIR)/lib
BINDIR = $(ROOTDIR)/bin
And the file definitions are:
MKFILE = $(BLDDIR)/Makefile
HDRFILES = $(wildcard $(INCDIR)/*.hpp)
LIBSRCFILES := $(wildcard $(LIBSRCDIR)/*.cpp)
TESTSRC = $(TESTSCRCDIR)/test.cpp
LIBOBJFILES := $(patsubst $(LIBSRCDIR)/%.cpp, $(LIBOBJDIR)/%.o, $(LIBSRCFILES))
TESTOBJ := $(TESTOBJDIR)/test.o
LIBFILE = $(LIBDIR)/$(NAME)-$(VERSION).a
TESTFILE = $(BINDIR)/test
ZIPFILE = $(ROOTDIR)/$(NAME).$(VERSION).zip
I have tested & confirmed that everything works, but for some reason $(TESTSRC) is printing empty even though Make is able to set $(TESTOBJ). I tried setting up the variable definitions in the hierarchy to ensure everything is generated in level, but that one variable remains empty.
EDIT 1:
Make is finding all of the directories properly
I have made sure that the file extension is correct
The variable is not being overwritten
EDIT 2:
The specific error I"mg getting is:
make: *** No rule to make target /test.cpp', needed by ..../test.o
..../test.o is in the right directory & defined separately without being dependent on a patsubst like the libsrc.
Read carefully:
TESTSRCDIR = $(SRCDIR)/test
^^^
and:
TESTSRC = $(TESTSCRCDIR)/test.cpp
^^^

Reassign Makefile variable for target

This is a simple Makefile:
...
VAR :=
FLAGS := --flag=$(VAR)
target_1: VAR = 1
target_1: $(DEPS_1)
$(CMD) $(FLAGS)
...
target_2: VAR = 2
target_2: $(DEPS_2)
$(CMD) $(FLAGS)
...
I want to reassign variable VAR to make make recalculate value of FLAGS to use it for different targets, is there a way to do something like this?
Don't use simple expansion for FLAGS:
FLAGS := --flag=$(VAR)
is wrong; you want this:
FLAGS = --flag=$(VAR)
If you expand FLAGS immediately, the all the variables are expanded to whatever their value is at that point in the makefile. There is no opportunity to redo that later, because the variable reference is gone: it's replaced with the value.

How to use genrules with go:embed

I need to include some generated files (for example output from go-swagger) in a binary. Without bazel you can do that using go:generate in combination with go:embed:
package demo
//go:generate swagger generate spec -w . -o ./openapi.json
import "embed"
// Content contains openapi.json file generated via go-swagger from spec
//go:embed openapi.json
var Content embed.FS
I am trying to do the same thing with bazel. As a simple test I have have this BUILD.bazel file:
genrule(
name = "hellodata",
srcs = ["hello.go"],
outs = ["hello.txt"],
cmd = "cat $(SRCS) | tr A-Za-z N-ZA-Mn-za-m > $#",
)
go_library(
name = "hello",
srcs = ["hello.go"],
importpath = "wiggy.net/hello",
visibility = ["//visibility:public"],
embedsrcs = [":hellodata"],
)
with hello.go looking like this:
package hello
import (
_ "embed"
"io"
)
//go:embed hello.txt
var greeting []byte
func Hello(out io.Writer) error {
_, err := out.Write(greeting)
return err
}
The intention here is to have Hello output the rot13 of it's own source. When I try to compile this it successfully generates hello.txt (located in bazel-out/darwin_arm64-fastbuild/bin/hello.txt), but the compiler can not find it:
❯ bazel build //...
INFO: Analyzed 5 targets (0 packages loaded, 0 targets configured).
INFO: Found 5 targets...
ERROR: /Users/wichert/Hack/bzl/BUILD.bazel:14:11: GoCompilePkg hello.a failed: (Exit 1): builder failed: error executing command bazel-out/host/bin/external/go_sdk/builder compilepkg -sdk external/go_sdk -installsuffix darwin_arm64 -src hello.go -embedsrc bazel-out/darwin_arm64-fastbuild/bin/hello.txt -importpath wiggy.net/hello ... (remaining 12 argument(s) skipped)
Use --sandbox_debug to see verbose messages from the sandbox
compilepkg: /private/var/tmp/_bazel_wichert/e7573342ee9452df4c3dfa671d399a16/sandbox/darwin-sandbox/76/execroot/__main__/hello.go:8:12: could not embed hello.txt: no matching files found
INFO: Elapsed time: 0,112s, Critical Path: 0,04s
INFO: 2 processes: 2 internal.
FAILED: Build did NOT complete successfully
I noticed -embedsrc bazel-out/darwin_arm64-fastbuild/bin/hello.txt in the command line for the failing action in your question, so as a hunch I tried the equivalent on my machine:
//go:embed bazel-out/k8-fastbuild/bin/hello.txt
var greeting []byte
And that seemed to work.
This is not so great because configuration information gets embedded in the source files (indeed, on your mac machine it's darwin_arm64-fastbuild and on my linux machine it's k8-fastbuild), so now your source code is artificially platform dependent.
It looks like this feature is relatively new (https://github.com/bazelbuild/rules_go/issues/2775, https://github.com/bazelbuild/rules_go/issues/2986). I would file an issue with rules_go about this.
There also appears to be go_embed_data which might behave differently:
https://github.com/bazelbuild/rules_go/blob/master/docs/go/extras/extras.md#go_embed_data
To answer my own question: the trick is to use genrule to generate the file(s) to be embedded, and then use go_embed_data to embed them. A work BUILD.bazel looks like this:
genrule(
name = "hellodata",
srcs = ["hello.go"],
outs = ["hello.txt"],
cmd = "cat $(SRCS) | tr A-Za-z N-ZA-Mn-za-m > $#",
)
go_embed_data(
name = "hello_embed",
src = ":hellodata",
package = "hello",
var = "greeting",
)
go_library(
name = "hello",
srcs = [
"hello.go",
":hello_embed",
],
importpath = "wiggy.net/hello",
visibility = ["//visibility:public"],
)

Makefile issue with multiple variable assignment

I have issues assigning the same variable multiple times in Makefile.
I am making a kind of modular makefile where I only deal with components instead of every source file and include directory.
This first solution works fine
MainRootDir = Components/Main
include $(RootDir)/$(MainRootDir)/Main.mak
Debug_Includes += $(addprefix $(MainRootDir)/,$(Main_Includes))
Debug_ASM_Sources += $(addprefix $(MainRootDir)/,$(Main_ASM_Static))
Debug_CC_Sources += $(addprefix $(MainRootDir)/,$(Main_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/, $(Main_ASM_Config))
Debug_CC_Sources += $(addprefix $(CfgDir)/, $(Main_CC_Config))
AdderRootDir = Components/Adder
include $(RootDir)/$(AdderRootDir)/Adder.mak
Debug_Includes += $(addprefix $(AdderRootDir)/,$(Adder_Includes))
Debug_ASM_Sources += $(addprefix $(AdderRootDir)/,$(Adder_ASM_Static))
Debug_CC_Sources += $(addprefix $(AdderRootDir)/,$(Adder_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/, $(Adder_ASM_Config))
Debug_CC_Sources += $(addprefix $(CfgDir)/, $(Adder_CC_Config))
However, if I try to standardize the block by defining variables and Re-Assigning new value before adding the software component each time, it stops working:
SwcName = Main
SwcRootDir = Components/$(SwcName)
include $(RootDir)/$(SwcRootDir)/$(SwcName).mak
Debug_Includes += $(addprefix $(SwcRootDir)/,$($(SwcName)_Includes))
Debug_ASM_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_ASM_Static))
Debug_CC_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/, $($(SwcName)_ASM_Config))
Debug_CC_Sources += $(addprefix $(CfgDir)/, $($(SwcName)_CC_Config))
SwcName = Adder
SwcRootDir = Components/$(SwcName)
include $(RootDir)/$(SwcRootDir)/$(SwcName).mak
Debug_Includes += $(addprefix $(SwcRootDir)/,$($(SwcName)_Includes))
Debug_ASM_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_ASM_Static))
Debug_CC_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/, $($(SwcName)_ASM_Config))
Debug_CC_Sources += $(addprefix $(CfgDir)/, $($(SwcName)_CC_Config))
The issue is that the source files of component Main are defined multiple times.
As if the Adder block is also expanding SwcName with the value Main.
Any idea how to prevent this?
You are using recursively expanded variables (var = ...), which is the default. So make defers the evaluation of the right hand side of your assignments until the variable's value is really needed. Example:
a = 1
b += $(a)
a = 2
b += $(a)
.PHONY: all
all:
#echo $(b)
will print 2 2 instead of the 1 2 you expect because what make actually stored in variable b was $(a) $(a), which it evaluated only before passing the recipe of all to the shell. And at that time a has only one single value: the last one it has been assigned, that is, 2.
You could use simply expanded variables (var := ...), instead:
b :=
a := 1
b += $(a)
a := 2
b += $(a)
.PHONY: all
all:
#echo $(b)
which will print 1 2. Do not forget the apparently useless b :=: it tells make that b is not a recursively expanded variable but a simply expanded one. Different from the default form, the value assigned to a simply expanded variable is evaluated when it is defined, its expansion is not deferred until the variable's value is needed.
But repeating large portions of code as in what you show is not optimal. Indeed, repeating things is frequently needed with humans but almost never optimal with computers. If you are using GNU make, as suggested by tripleee, you could use a kind of user-defined function:
Debug_Includes :=
Debug_ASM_Sources :=
...
# $(1) is the current SwcName
define MY_FUNC
SwcRootDir := Components/$(1)
include $$(RootDir)/$$(SwcRootDir)/$$(1).mak
Debug_Includes += $$(addprefix $$(SwcRootDir)/,$$($(1)_Includes))
Debug_ASM_Sources += $$(addprefix $$(SwcRootDir)/,$$($$(1)_ASM_Static))
...
endef
and then:
$(foreach SwcName,Main Adder,$(eval $(call MY_FUNC,$(SwcName))))
Do not forget the $$ in the macro definition. They are needed. See the GNU make manual for the full explanation.
This is a matter of recursive vs simply expanded variables. I'm going to guess that Debug_Includes is not initialized with a := earlier on, which means it defaults to be a recursively expanded variable. Therefore it is set to $(RootDir)/$(SwcRootDir)/$(SwcName).mak, and the internal variables are only expanded when it is referenced (at which point SwcRootDir will be Components/$(SwcName)).
Try initializing your variables with := at the top of your file to make them simple. Then they will be assigned values right away, and the internal variables will be set to what they were at the time of the definition.

how to manage external dependencies of a golang project in a yocto recipe

I want to write a yocto recipe for a cross-compiled golang application with Yocto 2.4.1 but I cannot get external dependencies to work.
Can anyone help me?
current RECIPE_FILE: hello-world_%.bb
LICENSE = "CLOSED"
LIC_FILES_CHKSUM = ""
DESCRIPTION = "Hello world test with golang."
inherit go
COMPATIBLE_MACHINE = "(<machine>)"
DEPENDS = "go-cross-${TARGET_ARCH}"
GO_IMPORT = "hello-world"
SRC_URI = "<git_url>/${GO_IMPORT}.git;branch=${SRCBRANCH};tag=${PV}"
SRCBRANCH = "master"
PV = "0.01"
S = "${WORKDIR}/git"
do_compile() {
export GOPATH="${WORKDIR}/build"
export GOARCH="<machine_arch>"
export GOOS="linux"
export CGO_ENABLED="0"
go build src/${GO_IMPORT}/hello-world.go
}
do_install() {
install -d "${D}/${bindir}"
install -m 0755 "${WORKDIR}/build/hello-world" "${D}/${bindir}/hello-world"
}
RDEPENDS_${PN}-dev += "bash"
This recipe works fine for internal dependencies only. But how do I integrate external dependencies like "github.com/golang/protobuf/ptypes"?
PROJECT_FILE: hello-world.go
package main
import (
"fmt"
"github.com/golang/protobuf/ptypes"
)
func main() {
timestamp := ptypes.TimestampNow()
fmt.Println(timestamp)
}
Does anyone knows a solution for this use case?
Or does anyone know how "go-dep" could handle this?
Best regards
I used go dep for the deps, here's an example. Most trouble was about the proxy which is also solved in the recipe:
inherit go
LICENSE = "CLOSED"
LIC_FILES_CHKSUM = ""
DESCRIPTION = "Hello world test with golang."
COMPATIBLE_MACHINE = "(<machine>)"
DEPENDS += "go-dep-native"
GO_LINKSHARED = ""
GO_IMPORT = "<git_url>/hello-world.git"
SRC_URI = "<git_url>/${GO_IMPORT}.git;branch=${SRCBRANCH};tag=${PV}"
SRCBRANCH = "master"
do_compile() {
export SSH_AUTH_SOCK="${SSH_AUTH_SOCK}"
export HTTP_PROXY="${HTTP_PROXY}"
( cd ${WORKDIR}/build/src/${GO_IMPORT} && dep ensure -v )
}
do_compile[vardepsexclude] += "SSH_AUTH_SOCK HTTP_PROXY"
do_install() {
install -d "${D}/${bindir}"
install -m 0755 "${WORKDIR}/bin/<arch>/hello-world" "${D}/${bindir}/hello-world"
}
I believe there is only two types of dependencies
1. host dependencies (dependencies when the app compiling time in yocto)
in yocto recipe(.bb file) keep DEPENDS = "some lib"
target dependencies (dependencies when the app running time on board)
your yocto recipe RDEPENDS = "some lib"
hello.bb
DESCRIPTION =
LIC =
SRC_URI =
DEPENDS ="sqlite3"
inherit autools
you can add external go dependencies with SRC_URI:
SRC_URI = "\
<git_url>/${GO_IMPORT}.git;branch=${SRCBRANCH};tag=${PV} \
git://github.com/golang/protobuf/ptypes;protocol=https;name=ptype;destsuffix=${PN}-${PV}/src/github.com/golang/protobuf/ptypes \
"
SRCREV_ptype = "v0.1.0" <-- whatever revision you need (branch, tag, sha)

Resources