pax_global_header00006660000000000000000000000064146673732270014533gustar00rootroot0000000000000052 comment=87a2be281d7d7a27d501196ca4ec5e82324f4095 mrbuild-1.13/000077500000000000000000000000001466737322700131155ustar00rootroot00000000000000mrbuild-1.13/.gitignore000066400000000000000000000000321466737322700151000ustar00rootroot00000000000000mock_configs/generated *~ mrbuild-1.13/Makefile.common.footer000066400000000000000000000441151466737322700173460ustar00rootroot00000000000000# -*- Makefile -*- # This is a part of the mrbuild project: https://github.com/dkogan/mrbuild # # Released under an MIT-style license. Modify and distribute as you like: # # Copyright 2016-2019 California Institute of Technology # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # This is a common Makefile that can be used as the core buildsystem for # projects providing a library and some executables using this library. Please # see README.build.org for the documentation. # There are two ways to pass variables to make: # # make CFLAGS=-foo # and # CFLAGS=-foo make # # The former creates a "command line" variable and the latter an # "environment variable". In order to be able to modify a "command line" # variable (to add other flags, say), one MUST use 'override'. So one would have to do # # override CFLAGS += -bar # # without the "override" nothing would happen. I want to avoid this rabbithole # entirely, so I disallow "command line" variables for things that I modify. # # I only do this for xxxFLAGS becuase cross-building and installing in Debian # uses Make in this way. Hopefully this is safe enough $(foreach v,$(filter %FLAGS,$(.VARIABLES)),$(if $(filter command line,$(origin $v)), $(error '$v' not allowed as a make parameter. Please do "$v=xxxx make yyyy" instead of "make yyyy $v=xxxx"))) # Make sure I have the variables that must be defined. Libraries need an ABI and # TAIL version, while other need a plain VERSION MUST_DEF_VARIABLES := PROJECT_NAME $(if $(LIB_SOURCES),ABI_VERSION TAIL_VERSION,VERSION) $(foreach v,$(MUST_DEF_VARIABLES),$(if $($v),,$(error User MUST specify $v))) # The default VERSION string that appears as a #define to each source file, and # to any generated documentation (gengetopt and so on). The user can set this to # whatever they like VERSION ?= $(ABI_VERSION).$(TAIL_VERSION) # Default compilers. By default, we use g++ as a linker CC ?= gcc CXX ?= g++ NVCC ?= nvcc CC_LINKER ?= $(CXX) # used to make gcc output header dependency information. All source # files generated .d dependency definitions that are included at the # bottom of this file CCXXFLAGS += -MMD -MP # always building with debug information. This is stripped into the # -dbg/-debuginfo packages by debhelper/rpm later CCXXFLAGS += -g # I want the frame pointer. Makes walking the stack WAY easier CCXXFLAGS += -fno-omit-frame-pointer LIB_OBJECTS := $(addsuffix .o,$(basename $(LIB_SOURCES))) BIN_OBJECTS := $(addsuffix .o,$(basename $(BIN_SOURCES))) SOURCE_DIRS := $(sort ./ $(dir $(LIB_SOURCES) $(BIN_SOURCES))) # if the PROJECT_NAME is libxxx then LIB_NAME is libxxx # if the PROJECT_NAME is xxx then LIB_NAME is libxxx LIB_NAME := $(or $(filter lib%,$(PROJECT_NAME)),lib$(PROJECT_NAME)) LIB_TARGET_SO_BARE := $(LIB_NAME).$(SO) LIB_TARGET_SO_ABI := $(LIB_TARGET_SO_BARE).$(ABI_VERSION) LIB_TARGET_SO_FULL := $(LIB_TARGET_SO_ABI).$(TAIL_VERSION) LIB_TARGET_SO_ALL := $(LIB_TARGET_SO_BARE) $(LIB_TARGET_SO_ABI) $(LIB_TARGET_SO_FULL) BIN_TARGETS := $(basename $(BIN_SOURCES)) # all objects built for inclusion in shared libraries get -fPIC. We don't build # static libraries, so this is 100% correct $(LIB_OBJECTS): CCXXFLAGS += -fPIC CCXXFLAGS += -DMRBUILD_VERSION='"$(VERSION)"' # These are here to process the options separately for each file being built. # This allows per-target options to be set # # if DEB_BUILD_OPTIONS has "noopt" (we're building a debian package, and the # user requested no optimizations), I remove all -O and add -O0 # # otherwise, if no explicit optimization flags are given, I pass -O3 define massageopts $(if $(filter noopt,$(DEB_BUILD_OPTIONS)),$(filter-out -O%,$1) -O0,\ $1 $(if $(filter -O%,$1),,-O3)) endef # If no C++ standard requested, I default to c++0x define massageopts_cxx $(call massageopts,$1 $(if $(filter -std=%,$1),,-std=c++0x)) endef define massageopts_c $(call massageopts,$1) endef # define the compile rules. I need to redefine the rules here because my # C..FLAGS variables are simple (immediately evaluated), but the user # could have specified per-target flags that ALWAYS evaluate deferred-ly # # I add the warning options AT THE START of the flag list so that the user can # override these cc_build_rule = $(strip $(CXX) $(call massageopts_cxx,-Wall -Wextra $(CXXFLAGS) $(CCXXFLAGS) $(CPPFLAGS))) -c -o $@ $< c_build_rule = $(strip $(CC) $(call massageopts_c, -Wall -Wextra $(CFLAGS) $(CCXXFLAGS) $(CPPFLAGS))) -c -o $@ $< cu_build_rule = $(strip $(NVCC) $(call massageopts_c, -Wall -Wextra $(CUFLAGS) $(CPPFLAGS))) -c -o $@ $< cu_build_rule += --compiler-options "-Wall -Wextra $(CCXXFLAGS)" %.o:%.C $(cc_build_rule) %.o:%.cc $(cc_build_rule) %.o:%.cpp $(cc_build_rule) %.o:%.c $(c_build_rule) %.o:%.cu $(cu_build_rule) %.o: %.S $(CC) $(ASFLAGS) $(CPPFLAGS) -c -o $@ $< # gengetopt rule. If we have GENGETOPT_OPTIONS, use those; otherwise use some # sensible defaults. If we don't have -F set an --output-dir also %.h %.c: %.ggo gengetopt -i $< \ $(if $(GENGETOPT_OPTIONS),$(if $(filter -F%,$(GENGETOPT_OPTIONS)),,--output-dir $(dir $<))) \ $(or $(GENGETOPT_OPTIONS), -C -u -g $(VERSION) -F $* args -f $(notdir $*) -a $(notdir $*)) # this is how you build QT4 UIs. There's a tool to generate headers from # UI definitions. There's also a tool to generate metadata from QT # classes. This must be compiled and linked in. QT4_MOCS is a list of # all these extra objects needed by QT. Simply add $(QT4_MOCS) to your # objects list and magic happens. Similar with QT4_UI_HEADERS ui_%.h: %.ui uic-qt4 $< > $@ moc_%.cpp: %.h moc-qt4 $< > $@ ui_%.hh: %.ui uic-qt4 $< > $@ moc_%.cpp: %.hh moc-qt4 $< > $@ # Python docstring rules. I construct these from plain ASCII files to handle # line wrapping %.docstring.h: %.docstring < $^ sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$$/\\n"/;' > $@ EXTRA_CLEAN += *.docstring.h # by default I build shared libraries only. We known how to build static # libraries too, but I don't do it unless asked all: $(if $(strip $(LIB_SOURCES)),$(LIB_TARGET_SO_ALL)) $(if $(strip $(BIN_SOURCES)),$(BIN_TARGETS)) .PHONY: all .DEFAULT_GOAL := all ifeq ($(COND_DARWIN),) $(LIB_TARGET_SO_FULL): LDFLAGS += -Wl,--default-symver else $(LIB_TARGET_SO_FULL): LDFLAGS += -dynamiclib endif $(LIB_TARGET_SO_FULL): LDFLAGS += -shared -fPIC -Wl,$(if $(COND_DARWIN),-install_name,-soname),$(notdir $(LIB_TARGET_SO_BARE)).$(ABI_VERSION) $(LIB_TARGET_SO_BARE) $(LIB_TARGET_SO_ABI): $(LIB_TARGET_SO_FULL) ln -fs $(notdir $(LIB_TARGET_SO_FULL)) $@ # Here instead of specifying $^, I do just the %.o parts and then the # others. This is required to make the linker happy to see the dependent # objects first and the dependency objects last. Same as for BIN_TARGETS $(LIB_TARGET_SO_FULL): $(LIB_OBJECTS) $(CC_LINKER) $(LDFLAGS) $(filter %.o, $^) $(filter-out %.o, $^) $(LDLIBS) -o $@ # I make sure to give the .o to the linker before the .so and everything else. # The .o may depend on the other stuff. # # The binaries get an RPATH (removed at install time). I use a relative RPATH # (using $ORIGIN) to make the build reproducible: chrpath doesn't remove the # actual RPATH string from the binary, and the local build directory gets # embedded in the output # # Here $^ contains two flavors of LIB_TARGET (see next stanza), so I manually # remove one $(BIN_TARGETS): %: %.o $(CC_LINKER) $(RPATH_OPTION) $(LDFLAGS) $(filter %.o, $^) $(filter-out $(LIB_TARGET_SO_ABI),$(filter-out %.o, $^)) $(LDLIBS) -o $@ # The binaries link with the DSO, if there is one. I need the libxxx.so to build # the binary, and I need the libxxx.so.abi to run it. $(BIN_TARGETS): $(if $(strip $(LIB_SOURCES)),$(LIB_TARGET_SO_BARE) $(LIB_TARGET_SO_ABI)) %.$(SO).dump: %.$(SO) abi-dumper $< -o $@ EXTRA_CLEAN += *.$(SO).dump clean: rm -rf $(foreach d,$(SOURCE_DIRS),$(addprefix $d,*.a *.o *.$(SO) *.$(SO).* *.d moc_* ui_*.h*)) $(BIN_TARGETS) $(foreach s,.c .h,$(addsuffix $s,$(basename $(shell find . -name '*.ggo')))) $(EXTRA_CLEAN) distclean: clean .PHONY: distclean clean ########################### installation business ifneq (,$(filter install,$(MAKECMDGOALS))) ifeq ($(strip $(DESTDIR)),) $(error Tried to make install without having DESTDIR defined \ "make install" is ONLY for package building. \ What are you trying to do?) endif ifneq (,$(strip $(DIST_PY2_MODULES))) PY2_MODULE_PATH := $(shell python2 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") $(if $(PY2_MODULE_PATH),,$(error "Couldn't find the python2 module path!")) endif ifneq (,$(strip $(DIST_PY3_MODULES))) PY3_MODULE_PATH := $(shell python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") $(if $(PY3_MODULE_PATH),,$(error "Couldn't find the python3 module path!")) endif USE_DEBIAN_PATHS := $(wildcard /etc/debian_version) ifneq (,$(USE_DEBIAN_PATHS)) # we're a debian-ish box, use the multiarch dir DEB_HOST_MULTIARCH := $(shell dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null) USRLIB := usr/lib/$(DEB_HOST_MULTIARCH) else # we're something else. Do what CentOS does. # If /usr/lib64 exists, use that. Otherwise /usr/lib USRLIB := $(if $(wildcard /usr/lib64),usr/lib64,usr/lib) endif endif # I process the simple wildcard exceptions on DIST_BIN and DIST_INCLUDE in a # deferred fashion. The reason is that I need $(wildcard) to run at install # time, i.e. after stuff is built, and the files $(wildcard) is looking at # already exist DIST_BIN_ORIG := $(DIST_BIN) DIST_INCLUDE_ORIG := $(DIST_INCLUDE) DIST_BIN = $(filter-out $(wildcard $(DIST_BIN_EXCEPT)), \ $(wildcard $(or $(DIST_BIN_ORIG), $(BIN_TARGETS)))) DIST_INCLUDE = $(filter-out $(wildcard $(DIST_INCLUDE_EXCEPT) *.docstring.h), \ $(wildcard $(DIST_INCLUDE_ORIG))) MANDIR := usr/share/man # Generates the install rules. Arguments: # 1. variable containing the being installed # 2. target path they're being installed to define install_rule $(if $(strip $($1)), mkdir -p $2 && \ cp -r $($1) $2 && \ $(if $($(1)_EXCEPT_FINDSPEC),find $2 $($(1)_EXCEPT_FINDSPEC) -delete, true) ) endef # Redhat wants the various manpage section get their own subdir for some reason define move_manpages_for_redhat mkdir -p $(DESTDIR)/$(MANDIR)/man$1 && \ (mv $(DESTDIR)/$(MANDIR)/*.$1 $(DESTDIR)/$(MANDIR)/man$1 2>/dev/null || true) && \ (mv $(DESTDIR)/$(MANDIR)/*.$1.gz $(DESTDIR)/$(MANDIR)/man$1 2>/dev/null || true) && \ (rmdir $(DESTDIR)/$(MANDIR)/man$1 2>/dev/null || true) endef ifneq ($(strip $(LIB_SOURCES)),) install: $(LIB_TARGET_SO_ALL) endif install: $(BIN_TARGETS) $(DIST_DOC) $(DIST_MAN) $(DIST_DATA) # using 'cp -P' instead of 'install' because the latter follows links unconditionally ifneq ($(strip $(LIB_SOURCES)),) mkdir -p $(DESTDIR)/$(USRLIB) cp -P $(LIB_TARGET_SO_FULL) $(DESTDIR)/$(USRLIB) ln -fs $(notdir $(LIB_TARGET_SO_FULL)) $(DESTDIR)/$(USRLIB)/$(notdir $(LIB_TARGET_SO_ABI)) ln -fs $(notdir $(LIB_TARGET_SO_FULL)) $(DESTDIR)/$(USRLIB)/$(notdir $(LIB_TARGET_SO_BARE)) endif $(call install_rule,DIST_BIN, $(DESTDIR)/usr/bin) $(call install_rule,DIST_INCLUDE, $(DESTDIR)/usr/include/$(PROJECT_NAME)) $(call install_rule,DIST_DOC, $(DESTDIR)/usr/share/doc/$(PROJECT_NAME)) # I install the manpages normally. On Redhat I need to shuffle them into # different subdirectories. This is incomplete: sections that aren't simply # digits 1-9 will not be moved. "3perl" is an example I can think of that won't # work here. Good-enough for now $(call install_rule,DIST_MAN, $(DESTDIR)/$(MANDIR)) ifeq (,$(USE_DEBIAN_PATHS)) $(foreach s,1 2 3 4 5 6 7 8 9,$(call move_manpages_for_redhat,$s) && ) true endif $(call install_rule,DIST_DATA, $(DESTDIR)/usr/share/$(PROJECT_NAME)) $(call install_rule,DIST_PERL_MODULES,$(DESTDIR)/usr/share/perl5) $(call install_rule,DIST_PY2_MODULES, $(DESTDIR)/$(PY2_MODULE_PATH)) $(call install_rule,DIST_PY3_MODULES, $(DESTDIR)/$(PY3_MODULE_PATH)) # In filenames I rename __colon__ -> : # This is required because Make can't deal with : in rules for fil in `find $(DESTDIR) -name '*__colon__*'`; do mv $$fil `echo $$fil | sed s/__colon__/:/g`; done ifeq ($(COND_DARWIN),) # Remove rpaths from everything. /usr/bin is allowed to fail because # some of those executables aren't ELFs. On the other hand, any .so we # find IS en ELF. Those could live in a number of places, since they # could be extension modules for the various languages, and I thus look # for those EVERYWHERE ifneq ($(strip $(DIST_BIN)),) chrpath -d $(DESTDIR)/usr/bin/* 2>/dev/null || true endif find $(DESTDIR) -name '*.$(SO)' | xargs chrpath -d else # BSD. I need to strip out the RPATHs individually ifneq ($(strip $(DIST_BIN)),) # here $f is the built file $(foreach f,$(filter $(DIST_BIN),$(BIN_TARGETS)),install_name_tool -delete_rpath $(call RPATH,$f) $(DESTDIR)/usr/bin/$(notdir $f) && \$(NEWLINE)) true endif echo "bsd install-time stripping of rpath is incomplete:" echo "1. need py2 path" echo "2. does $(wildcard) work here? it will be expanded before those targets exist" echo "3. what about nested paths? test mrgingham" ifneq ($(strip $(DIST_PY3_MODULES)),) # here $f is the installed file $(foreach f,$(filter %$(PY_EXT_SUFFIX),$(wildcard $(DESTDIR)/$(PY3_MODULE_PATH)/$(DIST_PY3_MODULES)/*)),install_name_tool -delete_rpath $(call RPATH,$(patsubst $(DESTDIR)/$(PY3_MODULE_PATH)/%,%,$f)) $f && \$(NEWLINE)) true endif endif # Any perl programs need their binary path stuff stripped out. This # exists to let these run in-tree, but needs to be removed at # install-time (similar to an RPATH) ifneq ($(strip $(DIST_BIN)),) for fil in `find $(DESTDIR)/usr/bin -type f`; do head -n1 $$fil | grep -q '^#!.*/perl$$' && perl -n -i -e 'print unless /^\s* use \s+ lib \b/x' $$fil || true; done endif test -e $(DESTDIR)/usr/share/perl5 && find $(DESTDIR)/usr/share/perl5 -type f | xargs perl -n -i -e 'print unless /^\s* use \s+ lib \b/x' || true ifneq ($(strip $(DIST_BIN)),) # Everything executable needs specific permission bits chmod 0755 $(DESTDIR)/usr/bin/* endif .PHONY: install # I don't want any intermediate files. There's a good summary of this situation # by Masahiro Yamada here: # # https://lore.kernel.org/lkml/Y6WUlth8KrR6EcsI@bergen.fjasle.eu/T/ # # And this snippet of code is from his patch (except I exclude versions 4.4... # to support the "remake" tool). # # I don't want any intermediate files because: # - they are deleted after each build # - a missing intermediate file will NOT trigger a rebuild of targets that # depend on it # # A demo. Create this Makefile: # # # Marking all files intermediate using ".SECONDARY:" breaks this: a missing "b" # # doesn't trigger a rebuild of "a" # a: b # touch $@ # b: # touch $@ # # # A common chain of build steps. Without .SECONDARY some of these will be # # deleted after the initial build, and will be re-created in a subsequent build # %-GENERATED.c: %-generate # touch $@ # %.o: %.c # touch $@ # %.so: %-GENERATED.o # touch $@ # xxx-GENERATED.o: CFLAGS += adsf # # # Imitates .d files created with "gcc -MMD". Does not exist on the initial build # # (so the xxx-GENERATED.[co] files ARE seen as intermediate initially). But DOES # # exist on subsequence builds, so these files are NOT seen as intermediate # ifneq ($(wildcard xxx.so),) # xxx-GENERATED.o: xxx-GENERATED.c # endif # # clean: # rm -rf a b xxx-GENERATED.c xxx-GENERATED.o xxx.so # .PHONY: clean # # Then run # # make clean # touch a xxx-generate xxx.h # echo "\n*** Should build xxx stuff AND a,b; should NOT rm xxx-GENERATED.c" # make a xxx.so # echo "\n*** All built should do nothing" # make a xxx.so # # This # - creates the xxx... files that would exist in a source tree # - sets us with with "a" but not "b", so we SHOULD rebuild "a" # # So we should see the initial build create everything, and not delete anything; # and the subsequent build shoulnd't have to do anything. And we can see that it # doesn't do the right thing with or without .SECONDARY: # # The solution is to not have any intermediate files. We can mark everything as # not-intermediate with .NOTINTERMEDIATE:, but that's only available in make # 4.4, and apparently was buggy in the initial release. We can also explicitly # mention specific files as targets or prerequisites (for instance "___dummy___: # file1 file 2") but that can only be done by the specific Makefiles using # mrbuild, not mrbuild itself. So if we cannot have .NOTINTERMEDIATE: here, we # settle for .SECONDARY: this won't delete stuff after each build, but still has # the second problem: missing files will NOT trigger a rebuild. # # Masahiro Yamada's snippet: # # .NOTINTERMEDIATE is more correct, but only available on newer Make versions. # Make 4.4 introduced .NOTINTERMEDIATE, and it appears in .FEATURES, but the # global .NOTINTERMEDIATE does not work. We can use it on Make > 4.4. # Use .SECONDARY for older Make versions, but "newer-prereq" cannot detect # deleted files. ifneq ($(and $(filter notintermediate, $(.FEATURES)),$(filter-out 4.4%,$(MAKE_VERSION))),) .NOTINTERMEDIATE: else .SECONDARY: endif # the header dependencies -include $(addsuffix *.d,$(SOURCE_DIRS)) mrbuild-1.13/Makefile.common.header000066400000000000000000000236461466737322700173060ustar00rootroot00000000000000# -*- Makefile -*- # This is a part of the mrbuild project: https://github.com/dkogan/mrbuild # # Released under an MIT-style license. Modify and distribute as you like: # # Copyright 2016-2019 California Institute of Technology # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # osx COND_DARWIN := $(filter Darwin,$(shell uname -s)) SO := $(if $(COND_DARWIN),dylib,so) # Hacks to get spaces and newlines in places where Make would normally parse # them out SPACE := SPACE := $(SPACE) $(SPACE) define NEWLINE endef dirs_to_dotdot = $(subst $(SPACE),/,$(patsubst %,..,$(subst /, ,$1))) get_parentdir_relative_to_childdir = /$(call dirs_to_dotdot,$(patsubst $1%,%,$2)) RPATH_SUFFIX = $(call get_parentdir_relative_to_childdir,$(abspath .),$(dir $(abspath $1))) ifeq ($(COND_DARWIN),) RPATH = '$$ORIGIN'$(RPATH_SUFFIX) else RPATH = @executable_path$(RPATH_SUFFIX) endif RPATH_OPTION = -Wl,-rpath,$(call RPATH,$@) # This stuff defines variables (PY_EXT_SUFFIX) that could be used by the user # Makefile at parsing time. So this must be included BEFORE the rest of the user # Makefile PYTHON_VERSION_FOR_EXTENSIONS ?= 3 # 2 or 3 # Flags for python extension modules. See # http://notes.secretsauce.net/notes/2017/11/14_python-extension-modules-without-setuptools-or-distutils.html # # I build the python extension module without any setuptools or anything. # Instead I ask python about the build flags it likes, and build the DSO # normally using those flags. # # There's some sillyness in Make I need to work around. First, I produce a # python script to query the various build flags, but replacing all whitespace # with __whitespace__. The string I get when running this script will then have # a number of whitespace-separated tokens, each setting ONE variable # # I set up a number of variables: # # These come from Python queries. I ask Python about XXX and store the result # into PY_XXX # # PY_CC # PY_CFLAGS # PY_CCSHARED # PY_INCLUDEPY # PY_BLDSHARED # PY_LDFLAGS # PY_EXT_SUFFIX # PY_MULTIARCH # # These process the above into a single set of CFLAGS: # # PY_MRBUILD_CFLAGS # # These process the above into a single set of LDFLAGS: # # PY_MRBUILD_LDFLAGS # # These process the above into a DSO-building linker command # # PY_MRBUILD_LINKER # # When the user Makefile evaluates ANY of these variables I query python, and # memoize the results. So the python is invoked at MOST one time. Any Makefiles # that don't touch the PY_... variables will not end up invoking the python # thing at all # # Variables to ask Python about _PYVARS_LIST := CC CFLAGS CCSHARED INCLUDEPY BLDSHARED BLDLIBRARY LDFLAGS EXT_SUFFIX MULTIARCH ifneq ($(DEB_HOST_MULTIARCH),) # We have a debian multiarch. We're almost certainly cross-building with # Debian. Try to get the variables directly, using any-architecture python define _PYVARS_GET_CONFIG := import ast import sys prefixes = ("_sysconfigdata_", "_sysconfigdata_m_linux") sysconfig_paths = [d + "/" + prefix + "_$(DEB_HOST_MULTIARCH).py" for d in sys.path for prefix in prefixes] for filename in sysconfig_paths: try: f = open(filename) except: continue s = f.read() s = re.sub("^#.*", "", s, flags=re.M) s = re.sub("^[0-9a-zA-Z_]+ *= *", "", s, flags=re.M) conf = ast.literal_eval(s) break else: raise Exception("Could not find sysconfig file in any sys.path directories. Tried: {}".format(sysconfig_paths)) endef else _PYVARS_GET_CONFIG := conf = sysconfig.get_config_vars() endif # Python script to query those variables define _PYVARS_SCRIPT from __future__ import print_function import sysconfig import re # get "conf" dict $(_PYVARS_GET_CONFIG) for v in ($(foreach v,$(_PYVARS_LIST),"$v",)): if v in conf: print(re.sub("[\t ]+", "__whitespace__", "_PY_{}:={}".format(v, conf[v]))) endef # I eval this to actually invoke the Python and to ingest its results. I only # eval this ONLY when necessary. define query_python_extension_building_flags _PYVARS = $(shell python$(PYTHON_VERSION_FOR_EXTENSIONS) -c '$(_PYVARS_SCRIPT)') # I then $(eval) these tokens one at a time, restoring the whitespace $(foreach setvarcmd,$(_PYVARS),$(eval $(subst __whitespace__, ,$(setvarcmd)))) # Add the numpy include path. See https://bugs.debian.org/1067398 _PY_INCLUDEPY += $(shell $(or $(PKG_CONFIG),pkg-config) --cflags-only-I numpy 2>/dev/null) # pull out flags from CC, throw out the compiler itself, since I know better _FLAGS_FROM_PYCC = $(wordlist 2,$(words $(_PY_CC)),$(_PY_CC)) _PY_MRBUILD_CFLAGS = $(filter-out -O%,$(_FLAGS_FROM_PYCC) $(_PY_CFLAGS) $(_PY_CCSHARED) -I$(_PY_INCLUDEPY)) # In the python api I have to cast a PyCFunctionWithKeywords to a PyCFunction, # and the compiler complains. But that's how Python does it! So I tell the # compiler to chill _PY_MRBUILD_CFLAGS += -Wno-cast-function-type # similarly, with gcc-14 I get this without turning off this warning: # /usr/include/python3.12/object.h:142:9: error: initialization of 'long int' from 'void *' makes integer from pointer without a cast [-Wint-conversion] _PY_MRBUILD_CFLAGS += -Wno-int-conversion # This is how we link the extension module DSOs. Note that we do NOT link with # -lpython, or anything of the sort (from $(_PY_BLDLIBRARY)). This isn't # strictly necessary because this will only be linked from the python # executable, so the library will already be loaded. And in some situations # (static linking), passing $(_PY_BLDLIBRARY) by itself doesn't actually work: # https://github.com/dkogan/mrcal/issues/22 _PY_MRBUILD_LDFLAGS = $(RPATH_OPTION) $(_PY_LDFLAGS) -L$(abspath .) _PY_MRBUILD_LINKER = $(_PY_BLDSHARED) endef # List of variables a user Makefile could touch. These are all PY_... _PYVARS_API := $(foreach v,$(_PYVARS_LIST),PY_$v) PY_MRBUILD_CFLAGS PY_MRBUILD_LDFLAGS PY_MRBUILD_LINKER # The first time the user touches these variables, ask Python. Each subsequent # time, use the previously-returned value. So we query Python at most once. If a # project isn't using the Python extension modules, we will not query Python at # all # # I handle all the Python API variables identically, except for PY_EXT_SUFFIX. # If Python gives me a suffix, I use it (this is available in python3; it has # ABI, architecture details). Otherwise, I try the multiarch suffix, or if even # THAT isn't available, just do .so. I need to handle it specially to make the # self-referential logic work with the memoization logic define _PY_DEFINE_API_VAR $1 = $$(or $$(_$1),$$(eval $$(value query_python_extension_building_flags))$$(_$1)) endef define _PY_DEFINE_API_VAR_EXTSUFFIX $1 = $$(or $$(_$1),$$(eval $$(value query_python_extension_building_flags))$$(or $$(_$1),$$(if $$(PY_MULTIARCH),.$$(PY_MULTIARCH)).$$(SO))) endef $(foreach v,$(filter-out PY_EXT_SUFFIX,$(_PYVARS_API)),$(eval $(call _PY_DEFINE_API_VAR,$v))) $(eval $(call _PY_DEFINE_API_VAR_EXTSUFFIX,PY_EXT_SUFFIX)) # Useful to pull in a local build of some library. For testing. Sets the # compiler and linker (runtime and build-time) flags. Invoke like this: # $(eval $(call add_local_library_path,/home/user/library)) define add_local_library_path CFLAGS += -I$1 CXXFLAGS += -I$1 LDFLAGS += -L$1 LDFLAGS += -Wl,-rpath,$1 endef #### VERSION_FROM_PROJECT variable: parse git tags or, if those aren't #### available, the debian/changelog. To use this, add to your Makefile: #### #### VERSION := $(VERSION_FROM_PROJECT) #### #### Otherwise, we'll use $(ABI_VERSION).$(TAIL_VERSION). VERSION_FROM_PROJECT #### is useful in mature-ish projects that are actually being distributed to #### others # "git describe --tags" says things like "v2.0-17-gcef328f". This converts it to "v2.0" _VERSION_STRIP_POST_TAG_ANNOTATIONS := s/-\d+-g[0-9a-f]+$$// # I might have a tag such as "debian/2.0-1". This converts it to "2.0-1" _VERSION_STRIP_LEADING_PATH := s/^.*\/// # I might have a tag such as "v2.0". This converts it to "2.0" _VERSION_STRIP_LEADING_V := s/^v//g # Custom version from git (or from debian/changelog if no git repo available) # If user says "VERSION_USE_LATEST_TAG=1 make" I'll use the latest tag for the # version, without annotations about the subsequent commits PAREN0 := ( PAREN1 := ) _VERSION = $(shell \ if test -e debian/changelog; then \ < debian/changelog perl -ane 'if($$F[1] =~ /^\$(PAREN0)(.+)\$(PAREN1)$$/) { print $$1 } else { print "VERSION_UNKNOWN"}; exit 0'; \ elif test -d .git && git describe --tags >/dev/null 2>/dev/null; then \ git describe --tags | \ perl -pe '$(if $(VERSION_USE_LATEST_TAG),$(_VERSION_STRIP_POST_TAG_ANNOTATIONS)); \ $(_VERSION_STRIP_LEADING_PATH); \ $(_VERSION_STRIP_LEADING_V);'; \ else \ echo "VERSION_UNKNOWN"; \ fi \ ) # Memoize. $(VERSION) will evaluate the result the first time, and use the # cached result during subsequent calls VERSION_FROM_PROJECT = $(if $(_VERSION_EXPANDED),,$(eval _VERSION_EXPANDED:=$$(_VERSION)))$(_VERSION_EXPANDED) mrbuild-1.13/README.org000066400000000000000000000374741466737322700146020ustar00rootroot00000000000000* SYNOPSIS This project is meant to provide some GNU Makefiles to take the boilerplate away from defining a project build. For instance: #+BEGIN_SRC makefile include /usr/include/mrbuild/Makefile.common.header PROJECT_NAME := foo ABI_VERSION := 0 TAIL_VERSION := 1 # Build all .c sources into a library: libfoo. If all library sources are in # src/, you can put $(wildcard src/*.c() here. Raw wildcards are not allowed in # LIB_SOURCES LIB_SOURCES := $(wildcard *.c) # build executable foo_tst from foo_tst.cc; it will be linked with libfoo # build executable foo_run from foo_run.cc; it will be linked with libfoo # # These should be separate from LIB_SOURCES. If all non-library sources are in # bin/, you can put $(wildcard bin/*.c) here. Raw wildcards are not allowed in # BIN_SOURCES BIN_SOURCES := foo_tst.c foo_run.c # Any extra flags. The build system always builds with debugging information and # (if no other -O flag is given) with optimization CCXXFLAGS += -Wno-unused-parameter # Extra libraries to link with. The library is linked with this. The executables # are linked with this AND with the library LDLIBS += -lbar # distribute (in a 'make install' and thus into the package) all headers except # those that match *tst* DIST_INCLUDE := *.h DIST_INCLUDE_EXCEPT := *tst* # distribute (in a 'make install' and thus into the package) all executables # built from BIN_SOURCES (foo_tst, foo_run) except *_tst, so only foo_run is # distributed DIST_BIN_EXCEPT := *_tst include /usr/include/mrbuild/Makefile.common.footer #+END_SRC * DESCRIPTION When defining the build rules for a project, there's often much boilerplate involved, the provenance of which is often lost to time. And there's usually much cargo-culting, and every project effectively forks the build scripts. The results aren't good, and mrbuild attempts to organize this. mrbuild provides a consistent set of =Makefiles= and project tree layout conventions. These make it easy to get friendly and consistent builds. A project that uses mrbuild is defined by a single =Makefile=. This is done by defining some variables and =include=-ing =Makefile.common.header=, =Makefile.common.footer= from =mrbuild=. Those files produce the rules that =make= uses to do its job. Note that unlike the CMake-based system, this is a one-step process: we don't create =Makefiles= and then use them to build stuff; we just build the stuff. Each project builds a library (a /shared/ object) and optionally, some executables. mrbuild knows how to build commonly-used things: QT interfaces, python extensions, etc. Intentionally, there's no mechanism to "find" dependency libraries: you should know where your dependencies live, and you can tell Make yourself the normal way: with =CFLAGS= and =LDFLAGS=. mrbuild will set up the =RPATH= tags to make the current directory findable. Thus executables can be run without installing, and they will link with the locally-built library. At install-time these =RPATH= tags will be stripped-away, so no extra steps are required when building packages. The project build definition file is a plain =Makefile=, so no special syntax and rules need to be mentioned here. And because it's a plain =Makefile=, we can define whatever arbitrary rules we want for anything not specifically covered by mrbuild. Furthermore, again since this is a plain =Makefile=, we can pass it external options in the environment. For instance, if we want to build without optimizations, simply invoke #+BEGIN_EXAMPLE CCXXFLAGS=-O0 make #+END_EXAMPLE The build system will pick up the new build option, and is smart enough to replace the default of =-O3= with the given =-O0=. Note that this is subtly different from #+BEGIN_EXAMPLE make CCXXFLAGS=-O0 #+END_EXAMPLE This latter invocation is /not/ supported, and we throw an error if this is encountered. ** API A complete list of the variables =mrbuild= knows about: *** Variables that MUST be defined - =PROJECT_NAME= The name of the project. Ends up in the SONAME. Libraries may or may not be called =lib...=, but the =lib= will be prepended to the SONAME if it's missing. - =ABI_VERSION= Required for libraries. An integer indicating the version of the ABI. Usually the same as the major version number of the project. Together with =TAIL_VERSION=, these define the default #+BEGIN_EXAMPLE VERSION ?= $(ABI_VERSION).$(TAIL_VERSION) #+END_EXAMPLE which can be used in the per-project =Makefile= - =TAIL_VERSION= Required for libraries. An arbitrary string. Together with =ABI_VERSION=, these define the default #+BEGIN_EXAMPLE VERSION ?= $(ABI_VERSION).$(TAIL_VERSION) #+END_EXAMPLE which can be used in the per-project =Makefile= - =VERSION= Required for non-libraries, optional for libraries. The version string. The project =Makefile= can set this to whatever. If omitted, it defaults to #+BEGIN_EXAMPLE VERSION ?= $(ABI_VERSION).$(TAIL_VERSION) #+END_EXAMPLE If =VERSION= and =ABI_VERSION= and =TAIL_VERSION= are all defined, the library SONAME comes from the ABI and TAIL versions, but the documentation will have the VERSION string. The compiler gets a preprocessor =#define= that can be used in the sources; this is called =MRBUILD_VERSION=. It isn't just =VERSION= to avoid conflicts with other symbols the code may be using. *** Build variables that MAY be defined - =LIB_SOURCES= Sources to build into a library. If omitted, no library will be built. Wildcards are /not/ allowed - =BIN_SOURCES= Sources to build into executables. By default each executable will be built from the library and each source in =BIN_SOURCES=. So if we have =a.c= and =b.c= in =BIN_SOURCES=, then two executables will be built: =a= and =b=, each linking in the library. Wildcards are /not/ allowed - =CFLAGS=, =CXXFLAGS=, =CCXXFLAGS=, =CPPFLAGS= Flags for C, C++, both and the preprocessor respectively. By default we pass =-O3= and (for C++) =-std=c++0x=. If we specify any other optimization level or standard, the defaults will be omitted. This is commonly used to build without optimizations: #+BEGIN_EXAMPLE CCXXFLAGS=-O0 make #+END_EXAMPLE In the =Makefile= these should be touched with =+== to not override any values passed in the environment. - =LDFLAGS= Similar to the above. Contains the linker flags. - =LDLIBS= Similar to the above. Contains the libraries we link with. By default this applies to all objects, libraries and executables we build. This is often overkill; if we want to apply some linker flag just to a particular object, use a per-target variable: #+BEGIN_SRC makefile BIN_SOURCES = a.c a: LDLIBS += -lbleh #+END_SRC *** Installation variables that MAY be defined The =DIST_...= variables are only looked-at if we =make install=, which in our world happens only when we're building a package. Generally =make install= copies the files indicated by the =DIST_...= variables to =DESTDIR=. - =DIST_BIN= Executables that we distribute. May include wildcards. If omitted, defaults to all the executables that =$(BIN_SOURCES)= produce - =DIST_INCLUDE= Headers that we distribute. May include wildcards. If omitted, no headers are distributed. - =DIST_BIN_EXCEPT=, =DIST_INCLUDE_EXCEPT= Simple distribution blacklists. May include wildcards. Anything that is matched by =DIST_XXX_EXCEPT= is /not/ distributed, even if it appears in =DIST_XXX=. For fancier logic, use the =..._FINDSPEC= variables described below - =DIST_DOC= Documentation we ship. May include wildcards. - =DIST_MAN= Man-pages we ship. May include wildcards. - =DIST_DATA= Arbitrary data we ship. May include wildcards. - =DIST_PERL_MODULES= Perl modules - =DIST_PY2_MODULES= Python2 modules - =DIST_PY3_MODULES= Python3 modules - =DIST_BIN_EXCEPT_FINDSPEC=, =DIST_INCLUDE_EXCEPT_FINDSPEC=, =DIST_DOC_EXCEPT_FINDSPEC=, =DIST_MAN_EXCEPT_FINDSPEC=, =DIST_DATA_EXCEPT_FINDSPEC= After we install a set of files to the =DESTDIR=, we may want to delete some subset of them. This is similar to the =..._EXCEPT= blacklists above, but accomplished with the =find= utility, so we have more flexibility. For instance, to install all the manpages except onces for tests, do this: #+BEGIN_SRC makefile DIST_MAN := doxygen-doc/man/man3 DIST_MAN_EXCEPT_FINDSPEC := -type f -name '*_test.3' #+END_SRC To install only the manpage for the =frobnicator= utility (delete all others) we do this: #+BEGIN_SRC makefile DIST_MAN := doxygen-doc/man/man3 DIST_MAN_EXCEPT_FINDSPEC := -type f \! \( -name 'frobnicator.3' \) #+END_SRC - =EXTRA_CLEAN= Additional targets to clean out during a =make clean= *** QT GUIs mrbuild has rules to handle QT moc and =.ui= stuff. An executable that uses QT can be defined like this: #+BEGIN_SRC makefile BIN_SOURCES := gui.cc MOC_OBJECTS := $(patsubst %.hh,moc_%.o,$(shell grep -l Q_OBJECT *.hh)) gui: $(MOC_OBJECTS) # gui.o will be linked in automatically #+END_SRC *** Manpages mrbuild knows how to install manpages, but not how to build them (this is usually project-specific). In my usage I do [[http://notes.secretsauce.net/notes/2018/10/23_manpages-and-readmes.html][this]], which I find quite useful. *** Python extensions mrbuild knows how to build python extension modules directly: without =distutils= or any such silliness. The result is that all the building is handled by =make=, and everything works the way it's supposed to. This is described in detail [[http://notes.secretsauce.net/notes/2017/11/14_python-extension-modules-without-setuptools-or-distutils.html][here]]. ** More complex example An annotated example showing some more complex usage appears in [[file:build_examples/GNU_Make/Makefile]], and is copied here #+BEGIN_SRC makefile # -*- Makefile -*- PYTHON_VERSION_FOR_EXTENSIONS := 3 include /usr/include/mrbuild/Makefile.common.header # This is a sample Makefile using the Makefile.common.header, # Makefile.common.footer infrastructure. A quick way to bootstrap a new project # is to copy this file to the root directory of the project and then to modify # each variable to fit that particular project. # The name of the project. By convention, libraries should be called lib... but # this isn't required PROJECT_NAME := libfrobnicator # The version of the library. We treat the major version as the version of the # ABI/API. So every time we change the ABI or an API in a backwards-incompatible # way, we bump the ABI_VERSION. If we make non-breaking changes, bumping the # TAIL_VERSION is sufficient. In this example, the full version is 0.1 ABI_VERSION := 0 TAIL_VERSION := 1 # Build all C and C++ sources in src/ into the library LIB_SOURCES := $(wildcard src/*.c*) # Build all C and C++ sources in bin/ into separate executables BIN_SOURCES := $(wildcard bin/*.c*) # If bin/run_foo.c exists, it is picked up in BIN_SOURCES, and the bin/run_foo # executable will be built from the library and bin/run_foo.o (built from # bin/run_foo.c). This is the default behavior and nothing needs to be specified # I specify that bin/run_foo2 consists of the library and bin/run_foo2.o (as # usual) AND links with bin/run_foo2_extra.o. The latter will be built from # bin/run_foo2_extra.c (or .cc or .cpp and so on, whichever exists) bin/run_foo2: bin/run_foo2_extra.o # Suppose I have bin/run_foo3.c to build bin/run_foo3. And suppose bin/run_foo3 # needs to additionally build with sources generated from run_foo3.in: the .o # links with bin/run_foo3_generated.o (built from bin/run_foo3_generated.c) and # the .c #includes run_foo3_generated.h, and that both of these are generated # from run_foo3.in. We specify this in the usual way, with a tiny bit of # mrbuild-specific stuff: run_foo3: run_foo3_generated.o run_foo3.o: run_foo3_generated.h %3_generated.h %3_generated.c: %3.in make_generated_files $< EXTRA_CLEAN += run_foo3_generated.h run_foo3_generated.c # If we're using gengetopt to generate the sources, the build rule and the # EXTRA_CLEAN list above are provided in mrbuild, and can be omitted. # Any extra flags to pass to the C and C++ compilers. The build system always # builds with debugging information and (if no other -O flag is given) with # optimization. Use += to not override any settings from the commandline CCXXFLAGS += -Wno-unused-parameter # Extra flags to pass to the C compiler when building src/bleh.o from src/bleh.c src/bleh.o: CFLAGS += -DFOO # Link bin/run_foo with -lbar. Do NOT link the library with -lbar. bin/run_foo: LDLIBS += -lbar # Link all the executables AND the library with -lzap LDLIBS += -lzap # If we have doxygen docs, we can state the rule to build them. Everything will # be built into doxygen-doc/, the DIST_DOC and DIST_MAN distribution lists below # install the man-pages and the html docs doc: doxygen-doc/ doxygen-doc/: frobnicator.dox SRCDIR='.' PROJECT='frobnicator' DOCDIR=$@ VERSION='$(VERSION)' PERL_PATH='/bin/perl' HAVE_DOT='YES' DOT_PATH='/bin' GENERATE_MAN='YES' GENERATE_RTF='NO' GENERATE_XML='NO' GENERATE_HTMLHELP='NO' GENERATE_CHI='NO' GENERATE_HTML='YES' GENERATE_LATEX='NO' doxygen $< doxygen-doc/%: doxygen-doc/ ; .PHONY: doc EXTRA_CLEAN += doxygen-doc # distribute (in a 'make install' and thus into the package) all headers in src/ # except those that match src/*tst* DIST_INCLUDE := src/*.h DIST_INCLUDE_EXCEPT := src/*tst* # distribute (in a 'make install' and thus into the package) all executables # built from BIN_SOURCES except bin/*_tst. And ship the python application DIST_BIN := $(filter-out bin/%_tst,$(wildcard $(BIN_TARGETS))) python-tool # distribute all generated manpages in section 3 EXCEPT those for the test # program DIST_MAN := doxygen-doc/man/man3 DIST_MAN_EXCEPT_FINDSPEC := -type f -name '*_tst.3' # distribute the html documentation DIST_DOC := doxygen-doc/html # This is the manpage-generating technique from # http://notes.secretsauce.net/notes/2018/10/23_manpages-and-readmes.html # # generate manpages from distributed binaries, and ship them. DIST_MAN += $(addsuffix .1,$(DIST_BIN)) $(DIST_MAN): %.1: %.pod pod2man --center="title: does something" --name=THING --release="thing 0.1" --section=1 $< $@ %.pod: % make-pod-from-help $< > $@ cat footer.pod >> $@ EXTRA_CLEAN += $(DIST_MAN) $(patsubst %.1,%.pod,$(DIST_MAN)) # This is the python-extension-generating technique from # http://notes.secretsauce.net/notes/2017/11/14_python-extension-modules-without-setuptools-or-distutils.html frobnicator_pywrap.o: CFLAGS += $(PY_MRBUILD_CFLAGS) frobnicator_pywrap.o: $(addsuffix .h,$(wildcard *.docstring)) frobnicator/_frobnicator$(PY_EXT_SUFFIX): frobnicator_pywrap.o libfrobnicator.so $(PY_MRBUILD_LINKER) $(PY_MRBUILD_LDFLAGS) $< -lfrobnicator -o $@ # The python libraries (compiled ones and ones written in python) all live in # frobnicator/ DIST_PY3_MODULES := frobnicator all: frobnicator/_frobnicator$(PY_EXT_SUFFIX) EXTRA_CLEAN += frobnicator/*.so include /usr/include/mrbuild/Makefile.common.footer #+END_SRC * MAINTAINER This is maintained by Dima Kogan * LICENSE AND COPYRIGHT Released under an MIT-style license. Modify and distribute as you like Copyright 2016-2019 California Institute of Technology Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. mrbuild-1.13/bin/000077500000000000000000000000001466737322700136655ustar00rootroot00000000000000mrbuild-1.13/bin/make-pod-from-help000077500000000000000000000115201466737322700171760ustar00rootroot00000000000000#!/usr/bin/perl use strict; use warnings; use feature ':5.10'; my $usagemessage = "Usage: $0 frobnicate > frobnicate.pod"; if(@ARGV != 1) { die "Need exactly one argument on the cmdline.\n$usagemessage"; } my $path = $ARGV[0]; if( ! (-r $path && -x $path && -f $path) ) { die "Commandline argument must be an executable file\n$usagemessage"; } # prepend ./ if no path given. I'm going to run this thing, so we need that $path = "./$path" unless $path =~ m{^/}; my $helpstring = `$path --help`; my $helpstring0 = $helpstring; # I assume the following stucture. If the --help string doesn't fit this # structure, I barf # # usage: frobnicator [-h] [--xxx XXX] # a [b ...] # # Does thing # # Synopsis: # # $ frobnicator xxx # ... blah blah # # $ more examples ... # # long description that talks about stuff # long description that talks about stuff # long description that talks about stuff # # long description that talks about stuff # # long description that talks about stuff # # positional arguments: # a Does what a does # # optional arguments: # b Does what b does # ... # usage is the thing up to the first blank line my ($usage) = $helpstring =~ m/(^usage.*?)\n\n/imsp or die "Couldn't parse out the usage; helpstring='$helpstring'"; $helpstring = ${^POSTMATCH}; my $helpstring1 = $helpstring; # Then we have a one-line summary my ($summary) = $helpstring =~ m/(^.*?)\n\n/p or die "Couldn't parse out the summary; helpstring='$helpstring'; helpstring0='$helpstring0'"; $helpstring = ${^POSTMATCH}; my $helpstring2 = $helpstring; # Then the synopsis my ($synopsis) = $helpstring =~ m/ ^synopsis.*?\n\n # synopsis title ( # capture stuff (?:(?:[ \t] .+?)? \n)+ # a bunch of lines: empty or beginning with whitespace ) # That's all I want /xpi or die "Couldn't parse out the synopsis; helpstring='$helpstring'; helpstring0='$helpstring0'; helpstring1='$helpstring1'"; $helpstring = ${^POSTMATCH}; my $helpstring3 = $helpstring; $synopsis =~ s/\n*$//g; # cull trailing whitespace # Now a description: everything until 'xxxx arguments'. I might not have a # description at all. I might also not have any "arguments" sections. my ($description, $post) = $helpstring =~ /(^.*?)(?:\n\n)?((?:\w+ arguments|options):?\n)/ips; if( defined $description) { $helpstring = $post . ${^POSTMATCH}; } else { # no arguments. Everything is a description. $description = $helpstring; $helpstring = ''; } my $helpstring4 = $helpstring; # Now the arguments my @args; while($helpstring !~ /^\s*$/) { # I see "required arguments" or "optional arguments" or "options" my ($argument_kind) = $helpstring =~ /(^\w+ arguments|options):?\n\n?/pi or die "Couldn't parse out argument kind; helpstring='$helpstring'; helpstring0='$helpstring0'; helpstring1='$helpstring1'; helpstring2='$helpstring2'; helpstring3='$helpstring3'; helpstring4='$helpstring4'"; $helpstring = ${^POSTMATCH}; my $helpstring5 = $helpstring; my ($argument_what) = $helpstring =~ /(^.*?)(?:\n\n|\n$)/pis or die "Couldn't parse out argument what; helpstring='$helpstring'; helpstring0='$helpstring0'; helpstring1='$helpstring1'; helpstring2='$helpstring2'; helpstring3='$helpstring3'; helpstring4='$helpstring4'; helpstring5='$helpstring5'"; $helpstring = ${^POSTMATCH}; # I really should parse the table argparse puts out, but let's just finish # this as is for now push @args, [uc($argument_kind), $argument_what]; } # Alrighty. I can now write out this thing say "=head1 NAME\n"; my ($programname) = $path =~ m{([^/]+$)} or die "Couldn't parse out the program name"; say "$programname - $summary\n"; say "=head1 SYNOPSIS\n"; say linkify($synopsis); say ""; if( $description ) { say "=head1 DESCRIPTION\n"; say linkify($description); say ""; } if(@args) { say "=head1 OPTIONS\n"; for my $arg (@args) { my ($kind,$what) = @$arg; $kind = "OPTIONAL ARGUMENTS" if $kind eq "OPTIONS"; say "=head2 $kind\n"; say linkify($what); say ""; } } sub linkify { $_[0] =~ s{https?://\S+}{L<${^MATCH}>}gps; return $_[0]; } __END__ =head1 NAME make-pod-from-help - creates POD documentation from a commandline tool =head1 SYNOPSIS $ make-pod-from-help frobnicate > frobnicate.pod =head1 DESCRIPTION This tool produces a POD from a C<--help> string. Primarily it's intended to work with Python tools using argparse. This tool generates a POD, which can then be made into a manpage with C. Some details L. =head1 REQUIRED ARGUMENTS =over =item Tool that we're making a manpage for =back =head1 AUTHOR Dima Kogan, C<< >> mrbuild-1.13/build_examples/000077500000000000000000000000001466737322700161125ustar00rootroot00000000000000mrbuild-1.13/build_examples/GNU_Make/000077500000000000000000000000001466737322700175005ustar00rootroot00000000000000mrbuild-1.13/build_examples/GNU_Make/Makefile000066400000000000000000000121301466737322700211350ustar00rootroot00000000000000# -*- Makefile -*- PYTHON_VERSION_FOR_EXTENSIONS := 3 include /usr/include/mrbuild/Makefile.common.header # This is a sample Makefile using the Makefile.common.header, # Makefile.common.footer infrastructure. A quick way to bootstrap a new project # is to copy this file to the root directory of the project and then to modify # each variable to fit that particular project. # The name of the project. By convention, libraries should be called lib... but # this isn't required PROJECT_NAME := libfrobnicator # The version of the library. We treat the major version as the version of the # ABI/API. So every time we change the ABI or an API in a backwards-incompatible # way, we bump the ABI_VERSION. If we make non-breaking changes, bumping the # TAIL_VERSION is sufficient. In this example, the full version is 0.1 ABI_VERSION := 0 TAIL_VERSION := 1 # Build all C and C++ sources in src/ into the library LIB_SOURCES := src/*.c* # Build all C and C++ sources in bin/ into separate executables BIN_SOURCES := bin/*.c* # If bin/run_foo.c exists, it is picked up in BIN_SOURCES, and the bin/run_foo # executable will be built from the library and bin/run_foo.o (built from # bin/run_foo.c). This is the default behavior and nothing needs to be specified # I specify that bin/run_foo2 consists of the library and bin/run_foo2.o (as # usual) AND links with bin/run_foo2_extra.o. The latter will be built from # bin/run_foo2_extra.c (or .cc or .cpp and so on, whichever exists) bin/run_foo2: bin/run_foo2_extra.o # Suppose I have bin/run_foo3.c to build bin/run_foo3. And suppose bin/run_foo3 # needs to additionally build with sources generated from run_foo3.in: the .o # links with bin/run_foo3_generated.o (built from bin/run_foo3_generated.c) and # the .c #includes run_foo3_generated.h, and that both of these are generated # from run_foo3.in. We specify this in the usual way, with a tiny bit of # mrbuild-specific stuff: run_foo3: run_foo3_generated.o run_foo3.o: run_foo3_generated.h %3_generated.h %3_generated.c: %3.in make_generated_files $< EXTRA_CLEAN += run_foo3_generated.h run_foo3_generated.c # If we're using gengetopt to generate the sources, the build rule and the # EXTRA_CLEAN list above are provided in mrbuild, and can be omitted. # Any extra flags to pass to the C and C++ compilers. The build system always # builds with debugging information and (if no other -O flag is given) with # optimization. Use += to not override any settings from the commandline CCXXFLAGS += -Wno-unused-parameter # Extra flags to pass to the C compiler when building src/bleh.o from src/bleh.c src/bleh.o: CFLAGS += -DFOO # Link bin/run_foo with -lbar. Do NOT link the library with -lbar. bin/run_foo: LDLIBS += -lbar # Link all the executables AND the library with -lzap LDLIBS += -lzap # If we have doxygen docs, we can state the rule to build them. Everything will # be built into doxygen-doc/, the DIST_DOC and DIST_MAN distribution lists below # install the man-pages and the html docs doc: doxygen-doc/ doxygen-doc/: frobnicator.dox SRCDIR='.' PROJECT='frobnicator' DOCDIR=$@ VERSION='$(VERSION)' PERL_PATH='/bin/perl' HAVE_DOT='YES' DOT_PATH='/bin' GENERATE_MAN='YES' GENERATE_RTF='NO' GENERATE_XML='NO' GENERATE_HTMLHELP='NO' GENERATE_CHI='NO' GENERATE_HTML='YES' GENERATE_LATEX='NO' doxygen $< doxygen-doc/%: doxygen-doc/ ; .PHONY: doc EXTRA_CLEAN += doxygen-doc # distribute (in a 'make install' and thus into the package) all headers in src/ # except those that match src/*tst* DIST_INCLUDE := src/*.h DIST_INCLUDE_EXCEPT := src/*tst* # distribute (in a 'make install' and thus into the package) all executables # built from BIN_SOURCES except bin/*_tst. And ship the python application DIST_BIN := $(filter-out bin/%_tst,$(wildcard $(BIN_TARGETS))) python-tool # distribute all generated manpages in section 3 EXCEPT those for the test # program DIST_MAN := doxygen-doc/man/man3 DIST_MAN_EXCEPT_FINDSPEC := -type f -name '*_tst.3' # distribute the html documentation DIST_DOC := doxygen-doc/html # This is the manpage-generating technique from # http://notes.secretsauce.net/notes/2018/10/23_manpages-and-readmes.html # # generate manpages from distributed binaries, and ship them. DIST_MAN += $(addsuffix .1,$(DIST_BIN)) $(DIST_MAN): %.1: %.pod pod2man --center="title: does something" --name=THING --release="thing 0.1" --section=1 $< $@ %.pod: % make-pod-from-help $< > $@ cat footer.pod >> $@ EXTRA_CLEAN += $(DIST_MAN) $(patsubst %.1,%.pod,$(DIST_MAN)) # This is the python-extension-generating technique from # http://notes.secretsauce.net/notes/2017/11/14_python-extension-modules-without-setuptools-or-distutils.html frobnicator_pywrap.o: CFLAGS += $(PY_MRBUILD_CFLAGS) frobnicator_pywrap.o: $(addsuffix .h,$(wildcard *.docstring)) frobnicator/_frobnicator$(PY_EXT_SUFFIX): frobnicator_pywrap.o libfrobnicator.so $(PY_MRBUILD_LINKER) $(PY_MRBUILD_LDFLAGS) $< -lfrobnicator -o $@ # The python libraries (compiled ones and ones written in python) all live in # frobnicator/ DIST_PY3_MODULES := frobnicator all: frobnicator/_frobnicator$(PY_EXT_SUFFIX) EXTRA_CLEAN += frobnicator/*.so include /usr/include/mrbuild/Makefile.common.footer