multi package makefile example for go - makefile

I'm trying to setup a multi package go project something like
./main.go
./subpackage1/sub1_1.go
./subpackage1/sub1_2.go
./subpackage2/sub2_1.go
./subpackage2/sub2_2.go
where main.go imports both subpackage1 and subpackage2. And subpackage2 imports subpackage1.
Ive been looking around for go makefile examples but I can't find anything that supports this kind of set-up. Any idea?

Install godag then run:
gd -o myapp
It will automatically build a Directed Acyclic Graph (DAG) of all the dependencies in your src/ directory, then compile and link each package in the proper order.
Much easier than manually maintaining a Makefile, especially since $(GOROOT)/src/Make.* has changed in recent versions of Go (there is no longer a Make.$(GOARCH)). Also useful:
gd clean removes object files.
gd -test runs your automated tests (see testing package).
gd -dot=myapp.dot generates a graph of your package imports you can visualize using GraphViz.

Something like this should work
# Makefile
include $(GOROOT)/src/Make.$(GOARCH)
all:main
main:main.$O
$(LD) -Lsubpackage1/_obj -Lsubpackage2/_obj -o $# $^
%.$O:%.go subpackage1 subpackage2
$(GC) -Isubpackage1/_obj -Isubpackage2/_obj -o $# $^
subpackage1:
$(MAKE) -C subpackage1
subpackage2:
$(MAKE) -C subpackage2
.PHONY:subpackage1 subpackage2
# subpackage1/Makefile
TARG=subpackage1
GOFILES=sub1_1.go sub1_2.go
include $(GOROOT)/src/Make.$(GOARCH)
include $(GOROOT)/src/Make.pkg
# subpackage2/Makefile
TARG=subpackage2
GOFILES=sub2_1.go sub2_2.go
include $(GOROOT)/src/Make.$(GOARCH)
include $(GOROOT)/src/Make.pkg
GC+=-I../subpackage1/_obj
LD+=-L../subpackage1/_obj
sub2_1.$O sub2_2.$O:subpackage1
subpackage1:
$(MAKE) -C ../subpackage1
.PHONY:subpackage1
If you don't install the subpackages you need to explicitly set the include path. The supplied makefile Make.pkg is mainly to build packages, which is why it's only included in the subpackage makefile.

hello world with a Makefile and a test (Googles Groupes : golang-nuts)

Check out https://github.com/banthar/Go-SDL which is an actively maintained multi-package go project using Makefiles.
I notice some of these the answers use the obsolete Make.$(GOARCH) include. So hopefully the above link will be stabler than trying to stay on top of Google's changing API in an answer here.

Related

Automatic dependency detection not working in GFortran

I the GCC Wiki it is stated that support for auto-detection of dependencies has been available since version 4.6:
Support the generation of Makefile dependencies via the -M... flags of GCC; you may need to specify additionally the -cpp option. The dependencies take modules, Fortran's include, and CPP's #include into account. Note: Using -M for the module path is no longer supported, use -J instead.
In my program I have two Fortran files: module_1.f08 and main.f08, where main uses module_1. I am using the following command to try to auto-detect dependencies of main:
gfortran -cpp -M main.f08
If module_1 has been already compiled, the command above returns a list of dependencies as expected, though if module_1 has not been compiled yet, I get an error message instead saying that module_1.mod does not exist.
The way I'm seeing this is that every time a new module is added to the code, it has to be compiled separately before running make all (or we might run make all before using the module in any other file, then use the module and compile again) or else any dependency of it might be compiled before the module itself and a compilation error will be returned.
Another thing is that dependency files have to be created gradually and one-by-one as the project grows, and if .mod files and dependency files got deleted at some point (with a make clean command for example), there will be no way to generate dependency files all at once using the auto-detection feature.
Is there a way to get around these limitations? Is there a way for auto-detection to work even if .mod files do not exist yet?
To start with, you need to add snippets to your Makefile to actually use the dependency generation feature. Additionally, you can use the -MD option to generate dependency files automatically for each target, so you don't need a special target to regenerate your dependencies. For an example project like yours above with a main.f90 that uses a module defined in mod1.f90 a simple Makefile using dependencies could look like:
FC := gfortran
FFLAGS := -O2 -g
LIBS := # Needed libs like -lopenblas
SRCS := mod1.f90 main.f90
OBJS := ${SRCS:f90=o}
DEPS := ${OBJS:o=d}
myprog: $(OBJS)
$(FC) $(FFLAGS) -o $# $^ $(LIBS)
.PHONY: clean
clean:
-rm -f $(OBJS) *.mod
-include $(DEPS)
%.o: %.f90
$(FC) $(FFLAGS) -cpp -MD -c -o $# $<
When you run make you'll see that it generates files main.d and mod1.d containing the dependencies for the corresponding source file.
A (minor?) problem here is that your SRCS variable containing your list of source files must be listed in an order that allows the files to be compiled from left to right before you have any .d files. So the dependency stuff as it's done here doesn't help with ordering a build before the .d files have been generated. (Thus I'd recommend distributing the .d files as part of the source package.)

GNU make - enforcing target order

Could someone please tell me if there is a way to enforce sequential execution of specific Makefile targets. For example, I have a Makefile that builds Libraries and Executables. Now, Executables depend on Libraries, so they must be built after the Libraries are built and staged. This is what I currently have in a single Makefile:
.PHONY: all
all: all_lib all_bin
.PHONY: all_lib
all_lib: $(dep_lib)
.PHONY: all_bin
all_bin: $(dep_bin)
I have two targets all_lib and all_bin, one builds all libraries and the other builds all binary executables. When I pass -j to make to run parallel jobs, I get build failures, because all targets run in parallel and binaries can't find shared library objects and staged header files.
I tried changing it to this to try and force some dependency order:
.PHONY: all
all: all_bin
.PHONY: all_lib
all_lib: $(dep_lib)
.PHONY: all_bin
all_bin: all_lib $(dep_bin)
But for some reason all targets still run in parallel I still get the same build failures. Any ideas?
Make is entirely built around the concept of dependencies. You are simply not using it that way.
If an executable depends on a library, then you should list that library in the prerequisites list of the executable. I can't give you a relevant example because you don't provide any details about the contents of dep_lib or dep_bin above, but for example:
exe1 : exe1.o liblib1.a liblib2.a
etc. Now, exe1 won't attempt to be linked until after the liblib1.a and liblib2.a targets have been created.

Guidance building Elixir package for OpenWRT

I'm looking to compile an Elixir package for OpenWRT, but am new to building Makefiles for OpenWRT.
I'm not sure where to start and plan to start by scaling down the erlang Makefile (https://github.com/openwrt/packages/blob/master/lang/erlang/Makefile) and start with erlang as it's only dependency.
I have looked for a guide on getting started with OpenWRT Makefiles, but have not found one.
Would anyone be willing to guide me through the process?
First, read this manual: http://wiki.openwrt.org/doc/devel/packages
Basically, you will need to create <openwrt-dir>/package/elixir directory and create a Makefile there like this:
include $(TOPDIR)/rules.mk
PKG_NAME:=elixir
PKG_REV:=0e3c06b03149022b980e69872003d401c4788fea
PKG_VERSION:=v1.1.0-rc.0
PKG_RELEASE=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/elixir-lang/elixir.git
PKG_SOURCE_VERSION:=$(PKG_REV)
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_REV).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=lang
CATEGORY:=Languages
TITLE:=Elixir
DEPENDS+= +erlang
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/elixir $(1)/usr/bin
# copy other files that are needed on target
endef
$(eval $(call BuildPackage,$(PKG_NAME)))
Then, issue make menuconfig command and select your newly created package.
After that, compile by running make package/elixir/install V=s and look if it compiles (it does on my machine).

How to create a non-transitive dependency list (GCC)

Is there a way to generate dependencies of a C(++) source file similar to using the -MM option of GCC that only include the direct dependencies of said file, i.e. only the files directly included by this source file?
More context on why I'm looking for this functionality - maybe there is a completely different solution to my problem: I have a generic makefile with auto-detection of dependencies that suffices my needs but is slow. The basic structure is as follows:
Full dependencies of main.cpp are retrieved with gcc -MM
All *.h dependencies for which a corresonding *.cpp exists are changed to *.o dependencies
the altered dependencies are included in the makefile
All *.o targets are built, dependencies are retrieved with gcc -MM and included
All *.o targets are linked to create the executable
So far, this makefile has worked fine but -as said before- it is slow. I analyzed its execution path for one project and included all the generated dependencies by hand to try and optimize its speed. The result was by removing all transitive dependencies, the makefile retained its functionality but got much faster (also reflected in the number of lines of the debug output of make -d).
First of all, the method you are using is slightly confusing. All .h files used in the compilation of one .cpp file must be kept in its dependencies, and the automatic collection of *.o files shouldn't be that slow. I'd advise to go with classic -MM and to build the list of cpp files that are to be compiled by hand. automake does it that way, and if there was a really reliable way of figuring out the list of compilation units automatically, these guys would have found it :-).
Nevertheless, the -H option of the gcc helps you. It prints the names of all used files to stderr, with . prefixed for the level of inclusion. So,
cpp -I $< >/dev/null | sed -n -e 's/^\. //p'
should do the trick. Caveat: If a header file is included deeper in the hierarchy first and then later in the main file, it is not found. However, your dependency system should be able to handle that if you keep the 1-to-1 of .h and .cpp files.

How to do a Makefile using a specific libraries in different paths?

The issue I'm having is that I need to compile my code using specific libraries that are in different path locations. I need to use -lncurses library from ./ramdisk/libs path, the problem is that this directory also cointains a version of lthr library that I don't want to be linked. The makefile is pulling both libraries from the same location which is not what I want. I can't change the contents of these library directories in the filesystem, so I need to find a way to tell the Makefile to link lncurses library from path A and link lthr library from path B instead using the lthr from path A.
Any suggestions?
CC=icc
NCE=-L./ramdisk/libs
CFLAGS+=-I$(ROOTDIR)/../../include
#LDFLAGS=-static -lthr
$(DESTDIR)/nce: nce
mkdir -p $(DESTDIR)
$(INSTALL) -m 777 nce $(DESTDIR)
nce: nce.c
$(CC) $(CFLAGS) nce.c $(LDFLAGS) -o nce -lthr $(NCE) -lncurses
You can (probably) bypass the search by giving the full path to the library archive. So instead of specifying -lncurses, you might try ./ramdisk/libs/libncurses.a (or whatever). You didn't specify whether it was a shared lib or not, and I'm not entirely sure that this works for shared libraries, but probably worth a try.
[edit]
Since this is a shared lib issues, maybe something like:
CC=icc
THR=/full/path/to/wherever/libthr/lives
NCE=/full/path/to/ramdisk/libs
CFLAGS+=-I$(ROOTDIR)/../../include
LDFLAGS=-static
nce: nce.c
$(CC) $(CFLAGS) nce.c $(LDFLAGS) -o nce -L$(THR) -W,-rpath=$(THR) -lthr -L$(NCE) -W,-rpath=$(NCE) -lncurses
I'm kind of shooting in the dark here as I'm not familiar with icc, but the idea is to make sure the linker puts thr's path on the runtime linker's search path before the one on the ramdisk so that thr gets found there first.
You could copy the remote library to a local working directory.
ncurses would source from one location while thr would source from another.

Resources