I want to have multiple binaries in one repository, but also set the version via ldflags option.
With just one binary in a repository I have no problem, it works, but with the new structure for multiple binaries it doesn't seem to work.
I have set up a simple project on github .
The structure is simple
cmd/
- server/main.go
- service/main.go
libcommon/
- version.go
- ...
go.mod
Makefile
version.go
package libcommon
var (
Version = "dev"
Build = "now"
)
Makefile
BUILDDIR = bin
VERSION := $(shell git describe --tags --always --dirty)
BUILD := $(shell date +%Y-%m-%d\ %H:%M)
LDFLAGS=-ldflags="-w -s -X 'libcommon.Version=${VERSION}' -X 'libcommon.Build=${BUILD}'"
go build ${LDFLAGS} -o $(BUILDDIR)/ ./...
I call make install and the binary is put into bin/ directory, but when I run it it just prints out the default values, not the ones I'd assume to be in there.
Any idea on how I can get to set the version with the ldflags in this layout?
Thanks in advance.
To correctly set the variable with -ldflags you have to qualify the variable name with the full package import path:
In Makefile:
LDFLAGS=-ldflags="-w -s \
-X 'mymodule.com/path/to/libcommon.Version=${VERSION}' \
-X 'mymodule.com/path/to/libcommon.Build=${BUILD}'"
build:
go build ${LDFLAGS} -o $(BUILDDIR)/ ./...```
Related
The problem I'm experiencing is an all target has dependencies on others that set a variable, then run matching dependencies.
Outcome - It will run the first dependency then stop.
Expected - Run both dependencies, setting the variable properly between each run
Is make smart enough to see pull and build were already ran and the dependency target itself has no execution, therefore it sees all dependencies as complete? Or I'm just abusing make in ways it should not be used?
Said makefile:
repo=rippio
image=default
pull:
#docker pull $(repo)/$(image):latest
build: pull
#sed -e 's/{{repo}}/$(repo)/' -e 's/{{image}}/$(image)/' Dockerfile.in > Dockerfile && \
docker build -t=$(repo)/$(image):custom .
#rm -f Dockerfile
node: image=node
node: | pull build
jdk8: image=jdk8
jdk8: | pull build
all: | node jdk8
TLDR
It is used to:
Pull the latest docker image
Run a generically designed Dockerfile against it to customize it
Tag it as :custom for internal use
Pretty handy for customizing images in a generic manner without managing many Dockerfiles.
Dockerfile template (Dockerfile.in), incase interested:
FROM {{repo}}/{{image}}:latest
... super secret sauce
UPDATE (ANSWER)
Thanks to #G.M., ended up with:
IMAGE_NAMES := node jdk8
TARGETS := $(patsubst %,build-%,$(IMAGE_NAMES))
repo=rippio
all: $(TARGETS)
build-%: pull-%
#$sed -e 's/{{repo}}/$(repo)/' -e 's/{{image}}/$*/' Dockerfile.in > Dockerfile-$* && \
$docker build -f=Dockerfile-$* -t=$(repo)/$*:custom .
#rm -f Dockerfile-$*
pull-%:
#$docker pull $(repo)/$*:latest
Which allows for:
Easy upkeep of 'all' targets, which constantly grows
Running parallel via make -j (note the Dockerfile-$* file pattern)
Much more beautiful than before
If you draw your dependency graph out long-hand you'll see that there are multiple paths from all to both pull and build -- one via each of node and jdk8. But make having reached/updated pull and build via one path will then assume that they are both up to date and, hence, not bother to update them further -- regardless of any change to target specific variables.
I think what you're trying to do (assuming I've understood correctly) might be more easily achieved using pattern rules.
IMAGE_NAMES := node jdk8
TARGETS := $(patsubst %,build-%,$(IMAGE_NAMES))
repo=rippio
all: $(TARGETS)
build-%: pull-%
#$sed -e 's/{{repo}}/$(repo)/' -e 's/{{image}}/$*/' Dockerfile.in > Dockerfile && \
$docker build -t=$(repo)/$*:custom .
#rm -f Dockerfile
pull-%:
#$docker pull $(repo)/$*:latest
Note: You currently have all build recipes using the same input/output file DockerFile. That will cause problems if you ever want to use parallel builds -- make -j etc. It might be wise to use the stem from the pattern rule match to uniquely identify the output file if that's possible.
Normally, if you invoke make with:
make all
and if none of pull, build, node, jdk8 are existing files, make should build pull and build. If you see only pull being made, it can be because you invoke make without specifying a goal. In this case make builds the first target it finds in the Makefile (pull in your case).
Anyway, there are several strange aspects in your Makefile: you use order-only prerequisites on what looks like phony targets and these phony targets are not declared as such.
I am not sure I fully understand what you are trying to do but maybe something like this would be a good starting point:
repo=rippio
image=default
.PHONY: all build node jdk8
all: node jdk8
node: image = node
jdk8: image = jdk8
build node jdk8:
#docker pull $(repo)/$(image):latest && \
sed -e 's/{{repo}}/$(repo)/' -e 's/{{image}}/$(image)/' Dockerfile.in > Dockerfile && \
docker build -t=$(repo)/$(image):custom . && \
rm -f Dockerfile
Note: if, instead of build you name the default target default you could even simplify further with:
repo=rippio
.PHONY: all default node jdk8
all: node jdk8
default node jdk8:
#docker pull $(repo)/$#:latest && \
sed -e 's/{{repo}}/$(repo)/' -e 's/{{image}}/$#/' Dockerfile.in > Dockerfile && \
docker build -t=$(repo)/$#:custom . && \
rm -f Dockerfile
This is a continuation of Makefile: run the same command with different arguments on different targets.
Code
COMMIT := $(shell git rev-parse HEAD)
images := base web proxy lb users api
$(images): base
#echo "Building $#"
docker build -f Dockerfile.$# --no-cache=true -t $#:$(COMMIT) .
build: $(images)
rebuild: $(images) # I want this to run with --no-cache=true
Essentially, build calls all image targets (base being the first one), and runs docker build with --no-cache=true for each one.
The problem
I would like to have a rebuild target which runs all image targets with --no-cache=false rather than --no-cache=true, without duplicating the code. I guess that the right way is to set a variable in rebuild and build whose scope would cover dependent targets like any of the images.
My question
How do I define a variable in a target whose scope covers all dependent targets?
Quite similar, like in mentioned question:
images := base web proxy lb users api
$(images):
#echo $# docker --no-cache=$(NO_CACHE)
build: NO_CACHE=true
rebuild: NO_CACHE=false
rebuild build: $(images)
You may want to set a default value for NO_CACHE in case you would like to call make base for example.
I am developing in XCode on Mac OS X El Capitan 10.11.4. My project mixes C, C++11 and Embedded Python.
My project works as I can invoke a Python script and return the data to C++ by embedding python. In my project I use absolute paths as pythons search path to load the script from 'C'.
XCode project/
-- Python.framework/
-- python/
---- mypython.py
-- python_interface.c
-- main.cpp
My questions are:
Q1: I have brew Python available but this isn't seen from XCode, instead the system supplied one is. This isn't a problem for now but I would eventually like to know how to point to my chosen installation.
I have bundled the brew Python.framework into my project so it links successfully. I know it doesn't invoke this because if I specify my module path incorrectly it complains the system python can not find it. Also, 'system(which python)' reports '/usr/bin/python'.
Q2: How do I specify relative search paths to python within XCode, i.e. to locate my local python module from 'C' code within my project?
Q3: How do I determine the absolute path of python 'requests' installation at runtime? My python module imports this and it could be different than what I specify.
Currently, I use Py_GetPath and Py_SetPath to indicate these using absolute paths, i.e. '/usr/local/lib/python2.7/site-packages' for 'requests'.
I know how to locate the module path within python itself (Find path of module without importing in Python) but this is not what I want to do. I need to know the path before my script is run.
As mentioned I am embedding python, so I am making the call from 'C' to my python script (see https://docs.python.org/2/extending/embedding.html?highlight=embedded#pure-embedding).
I have found the following links that show how to get the path of the executable. What I would like is the path of the project and use relative paths from that to locate my python module.
Relative Paths Not Working in Xcode C++
Programmatically retrieving the absolute path of an OS X command-line app
I have found this posting; Relative imports for the billionth time. My search path from 'C' code to my python script is relative but I believe this post is mainly about python scripts importing other modules relative to each other.
Q4: The result of adding or linking Frameworks to an XCode project is the same. In my case the Python.framework appears in the 'Project navigator' and it is added to the 'Link Binaries With Libraries' section. Yet the following two articles indicate that there is a difference between the two. It is not the size of the executable as I have tried both methods and this remains the same.
https://developer.apple.com/library/ios/recipes/xcode_help-structure_navigator/articles/Adding_a_Framework.html
This states;
"The frameworks you add this way are third-party-built bundles containing the framework’s object code and runtime resources. See related articles for information about linking to a framework without adding it to the project."
and contains a link to "Linking to a Library or Framework", whose url seems to contradict this (AddingaLibrarytoaTarget).
https://developer.apple.com/library/ios/recipes/xcode_help-project_editor/Articles/AddingaLibrarytoaTarget.html#//apple_ref/doc/uid/TP40010155-CH17
Thanks.
Some answers to my questions
I reorganised my project and created my own Makefile using various sources on google. This was because I wanted to port my project as I couldn't answer the above questions. I had worked with Makefiles some years before but I am relatively new to XCode.
To create my Makefile these are the resources I used;
https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html
C-library not linking using gcc/g++
https://www.daniweb.com/programming/software-development/threads/124637/makefile-for-c-one-file-programs
https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables
http://www.puxan.com/web/blog/HowTo-Write-Generic-Makefiles
https://www.gnu.org/software/make/manual/
http://nuclear.mutantstargoat.com/articles/make/#building-c-c-programs
https://www.gnu.org/software/make/manual/html_node/index.html
The next step is to automate the process of generating Makefiles;
http://www.ifnamemain.com/posts/2014/Mar/13/autoconf_automake/
New Makefile project structure
project/
-- Debug/ or Release/
-- Makefile
-- obj/
---- target .o files
-- python/
---- .py files
-- src/
---- C/C++ files incl headers
Makefile
# https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables
# $# Contains the target file name.
# $< Contains the first dependency file name.
# $^ The names of all the prerequisites, with spaces between them.
# Produces a Release build by default, or Debug build with ‘make debug’
EXEC = $(BUILD_DIR)/my_exe_name
CCFLAGS=-c -Wall
CXXFLAGS=-c -Wall -std=c++11
BINARY_DIR=Obj
BUILD_DIR=Release
PYTHON_CCFLAGS=$(shell python2.7-config --cflags)
PYTHON_LDFLAGS=$(shell python2.7-config --ldflags)
CPP_FILES := $(wildcard src/*.cpp)
C_FILES := $(wildcard src/*.c)
CPP_OBJ_FILES := $(addprefix $(BINARY_DIR)/,$(notdir $(CPP_FILES:.cpp=.o)))
C_OBJ_FILES := $(addprefix $(BINARY_DIR)/,$(notdir $(C_FILES:.c=.o)))
C_HEADERS = $(filter-out $(addsuffix .h, $(basename $(SOURCE_FILES))), $(wildcard src/*.h))
CPP_HEADERS = $(filter-out $(addsuffix .h, $(basename $(SOURCE_FILES))), $(wildcard src/*.hpp))
### Take the BUILD_DIR as a dependency but ignore it’s timestamp
### as it will change whenever something is written into it
$(EXEC): $(C_OBJ_FILES) $(CPP_OBJ_FILES) | ${BUILD_DIR}
#echo [ $(EXEC) ]
$(CXX) $(LD_FLAGS) $(PYTHON_LDFLAGS) -o $(EXEC) $^
### The objects in the BINARY_DIR folder require the BINARY_DIR to be created
### as well as any changes to the other dependencies
$(BINARY_DIR)/%.o: src/%.cpp $(CPP_HEADERS) $(C_HEADERS) | ${BINARY_DIR}
#echo [ make $# ]
$(CXX) $(CXXFLAGS) $(C11_FLAGS) -o $# $<
$(BINARY_DIR)/%.o: src/%.c $(C_HEADERS) | ${BINARY_DIR}
#echo [ make $# ]
$(CC) $(CCFLAGS) $(PYTHON_CCFLAGS) -o $# $<
${BINARY_DIR}:
mkdir $(BINARY_DIR)
$(BUILD_DIR):
mkdir $(BUILD_DIR)
### clean the targets. We can have either Debug or Release but I don’t know
### how to specify either in one line, i.e. we don’t want to do ‘make clean debug’
### to specify the Debug folder
.PHONY: clean cleanmsg cleanrel cleandeb
clean: cleanmsg cleanrel cleandeb
rm -r -f $(BINARY_DIR)
cleanmsg:
#echo Cleaning product and all .o files
cleanrel:
rm -r -f Release
cleandeb:
rm -r -f Debug
# Debug build
# Ensure these are last. I had them below the original decl of the flags
# and they were always set! Now you have to ‘make debug’ for it to take effect
.PHONY: debug
debug: CCFLAGS += -DDEBUG -g
debug: CXXFLAGS += -DDEBUG -g
debug: BUILD_DIR=Debug
debug: $(EXEC)
Using XCode with new Makefile project
To continue using XCode to develop my project I created an XCode project over my Makefile project. See http://hiltmon.com/blog/2015/08/01/simple-c-plus-plus-from-makefiles-to-xcode-builds/
Answers
By doing this I am able to somewhat answer the above questions. Q3 is still unanswered.
A1: Create a Makefile project and within it state the platform specified python installation. This way you do not need to bundle it into your XCode project.
See https://docs.python.org/2/extending/embedding.html?highlight=embedded#compiling-and-linking-under-unix-like-systems.
A2: Make the XCode project relative so your product resides in your project. Not the best answer if you want your exe installed in /usr/local/bin.
See How to change output directory for a target (gp_coder's answer).
My Makefile stores the exe in either ./Release/ (make), or ./Debug/ (make debug). So does XCode but with different leading directories that are several levels deep. To change this, simply specify the current dir '.' in XCode for the Targets "Project Settings>Advanced>Custom>Products" destination directory, this will then match the Makefile.
My python search path is set to
:../python:/usr/local/lib/python2.7/site-packages
'../' because my exe is in ./Debug or./Release and python/ is relative to that.
However, if you were to invoke the exe from the cmdline one dir up it wouldn't work. e.g. ./Release/my_exe_name. This is because it is taking the current dir and using the search path in relation to that.
It would be better to store and set the absolute path. See Where to store application data (non-user specific) on Linux
I posted a question on this before I realised the answer; How to set relative project path in XCode when target is /usr/local/bin
The second path is for my python requests directory. Q3 refers to this.
A3: Don't know. Still have to work out how to pass my installed python module path into my C code at runtime BEFORE invoking python, as this makes up my python search path. This value changes based on your installation.
A4: This wasn't really a question but a confusion. Specify this in your Makefile to avoid bundling.
I am new to Erlang, so i am going through Joe Armstrong's book "Programming Erlang". In chapter 25 there's an example on how to work with rebar. I followed the instructions and created a Makefile
all:
test -d deps || rebar get-deps
rebar compile -v
#erl -noshell -pa './deps/bitcask/ebin' -pa './ebin' -s myapp start
and rebar.config
{deps, [
{bitcask, ".*", {git, "git://github.com/basho/bitcask.git", "master"}}
]}.
Getting the dependencies works, but compiling fails.
The verbose output tells me that this command fails
cmd: cc -c $CFLAGS -g -Wall -fPIC -I"/usr/lib/erlang/lib/erl_interface-3.7.18/include" -I"/usr/lib/erlang/erts-6.2/include" c_src/bitcask_nifs.c -o c_src/bitcask_nifs.o
with this error
/home/user/folder/deps/bitcask/c_src/bitcask_nifs.c:22:19: fatal error: errno.h: No such file or directory
But
find /usr/include -name errno.h
gives me
/usr/include/x86_64-linux-gnu/asm/errno.h
/usr/include/asm/errno.h
/usr/include/linux/errno.h
/usr/include/asm-generic/errno.h
So I was asking myself..
what am I missing?
how can I tell rebar about the depencies on the C libraries and where to find them?
why isn't this configured correctly in the Makefile of bitcask?
Maybe I was searching for the wrong terms, but I couldn't find any solution in the internets.
Many thanks in advance
There are two thing to consider
rebar options
You can set options for compiling C code with port_env option in rebar.config.
comiling deps
Since bitstack is your dependency, it is not compiled with yours rebar config, but with it's own. So if you would like to change anything, you would have to modify the bitcask file.
Fortunately, if you look into config their writen all C compilation is done with environment variable $ERL_CFLAGS. And again, in rebar source code you can see that this flag is responsible for include paths in your compilation.
So easist way would be extending $ERL_CFLAGS in your Makefile before compilation, with something like this
all: ERL_CFLAGS = "$ERL_CFLAGS -I /usr/include/linux/errno.h"
all:
test -d deps || rebar get-deps
rebar compile -v
#erl -noshell -pa './deps/bitcask/ebin' -pa './ebin' -s myapp start
Just make sure that this include works for you, and that you are not overwriting any flags you are using.
I have just put together a Go package that is going to be a part in a fairly large system with a lot of shared packages. I was able to get it to compile by writing its Makefile such that the compiler is called with -I flags:
include $(GOROOT)/src/Make.inc
TARG=foobar
GOFILES=\
foobar.go\
foobar:
$(GC) -I$(CURDIR)/../intmath -I$(CURDIR)/../randnum foobar.go
include $(GOROOT)/src/Make.pkg
It compiles just fine, and being a good boy, I wrote a comprehensive set of tests. However, when I try to run the tests with gotest, I get a compile error:
$ gotest
rm -f _test/foobar.a
8g -o _gotest_.8 foobar.go foobar_test.go
foobar.go:4: can't find import: intmath
make: *** [_gotest_.8] Error 1
gotest: "C:\\msys\\bin\\sh.exe -c \"gomake\" \"testpackage\" \"GOTESTFILES=foobar_test.go\"" failed: exit status 2
So, the Go file itself will compile when I use the -I flags to tell it where to find the intmath and randnum packages, but gotest doesn't seem to use the Makefile.
Answering peterSO's question:
foobar.go's import section looks like this:
import (
"intmath"
"randnum"
"container/vector"
)
And the compile works fine as long as I have the -I flags going to the compiler. I have tried to use relative paths, like this:
import (
"../intmath"
"../randnum"
"container/vector"
)
but that just doesn't seem to work.
EDIT: answering further peterSO questions:
GOROOT is set to C:\Go the directory where I have all of the Go stuff -- aside from my source code -- installed. I was expecting the relative path to be relative to the directory in which the source file lives.
My source tree looks like this:
server/
foobar/
randnum/
intmath/
So, while I am open to a different, more Go-idiomatic directory structure, my instinct is to arrange them as peers.
Is there some way that I can nudge gotest into compiling foobar.go with the needed flags?
Create the Windows source code directory structure:
C:\server
C:\server\foobar
C:\server\intnum
For intnum.go:
package intnum
func IntNum() int {
return 42
}
Makefile:
include $(GOROOT)/src/Make.inc
TARG=server/intnum
GOFILES=\
intnum.go\
include $(GOROOT)/src/Make.pkg
Run:
$ cd c/server/intnum
$ make install
For foobar.go:
package foobar
import (
"math"
"server/intnum"
)
func FooBar() float64 {
return float64(intnum.IntNum()) * math.Pi
}
Makefile:
include $(GOROOT)/src/Make.inc
TARG=server/foobar
GOFILES=\
foobar.go\
include $(GOROOT)/src/Make.pkg
Run:
$ cd /c/server/foobar
$ make install
After the install, the intnum.a and foobar.a package files will be in the $GOROOT\pkg\windows_386\server (C:\Go\pkg\windows_386\server) directory`.