{"id":19795560,"url":"https://github.com/dkogan/mrbuild","last_synced_at":"2025-02-28T10:25:16.509Z","repository":{"id":60255959,"uuid":"141651165","full_name":"dkogan/mrbuild","owner":"dkogan","description":"Simple build system","archived":false,"fork":false,"pushed_at":"2024-09-08T19:11:27.000Z","size":211,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-01-11T04:50:18.110Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Makefile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dkogan.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-20T02:03:55.000Z","updated_at":"2024-09-08T19:11:23.000Z","dependencies_parsed_at":"2023-01-20T04:31:37.870Z","dependency_job_id":"59855f3c-aca4-4662-9b43-14033ffcec9a","html_url":"https://github.com/dkogan/mrbuild","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2Fmrbuild","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2Fmrbuild/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2Fmrbuild/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2Fmrbuild/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dkogan","download_url":"https://codeload.github.com/dkogan/mrbuild/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241137689,"owners_count":19916176,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T07:16:42.340Z","updated_at":"2025-02-28T10:25:16.475Z","avatar_url":"https://github.com/dkogan.png","language":"Makefile","funding_links":[],"categories":[],"sub_categories":[],"readme":"* SYNOPSIS\nThis project is meant to provide some GNU Makefiles to take the boilerplate away\nfrom defining a project build. For instance:\n\n#+BEGIN_SRC makefile\n\ninclude /usr/include/mrbuild/Makefile.common.header\n\nPROJECT_NAME := foo\nABI_VERSION  := 0\nTAIL_VERSION := 1\n\n# Build all .c sources into a library: libfoo. If all library sources are in\n# src/, you can put $(wildcard src/*.c() here. Raw wildcards are not allowed in\n# LIB_SOURCES\nLIB_SOURCES := $(wildcard *.c)\n\n# build executable foo_tst from foo_tst.cc; it will be linked with libfoo\n# build executable foo_run from foo_run.cc; it will be linked with libfoo\n#\n# These should be separate from LIB_SOURCES. If all non-library sources are in\n# bin/, you can put $(wildcard bin/*.c) here. Raw wildcards are not allowed in\n# BIN_SOURCES\nBIN_SOURCES := foo_tst.c foo_run.c\n\n# Any extra flags. The build system always builds with debugging information and\n# (if no other -O flag is given) with optimization\nCCXXFLAGS += -Wno-unused-parameter\n\n# Extra libraries to link with. The library is linked with this. The executables\n# are linked with this AND with the library\nLDLIBS += -lbar\n\n# distribute (in a 'make install' and thus into the package) all headers except\n# those that match *tst*\nDIST_INCLUDE        := *.h\nDIST_INCLUDE_EXCEPT := *tst*\n\n# distribute (in a 'make install' and thus into the package) all executables\n# built from BIN_SOURCES (foo_tst, foo_run) except *_tst, so only foo_run is\n# distributed\nDIST_BIN_EXCEPT     := *_tst\n\ninclude /usr/include/mrbuild/Makefile.common.footer\n#+END_SRC\n\n* DESCRIPTION\nWhen defining the build rules for a project, there's often much boilerplate\ninvolved, the provenance of which is often lost to time. And there's usually\nmuch cargo-culting, and every project effectively forks the build scripts. The\nresults aren't good, and mrbuild attempts to organize this. mrbuild provides a\nconsistent set of =Makefiles= and project tree layout conventions. These make it\neasy to get friendly and consistent builds.\n\nA project that uses mrbuild is defined by a single =Makefile=. This is done by\ndefining some variables and =include=-ing =Makefile.common.header=,\n=Makefile.common.footer= from =mrbuild=. Those files produce the rules that\n=make= uses to do its job. Note that unlike the CMake-based system, this is a\none-step process: we don't create =Makefiles= and then use them to build stuff;\nwe just build the stuff.\n\nEach project builds a library (a /shared/ object) and optionally, some\nexecutables. mrbuild knows how to build commonly-used things: QT interfaces,\npython extensions, etc. Intentionally, there's no mechanism to \"find\" dependency\nlibraries: you should know where your dependencies live, and you can tell Make\nyourself the normal way: with =CFLAGS= and =LDFLAGS=.\n\nmrbuild will set up the =RPATH= tags to make the current directory findable.\nThus executables can be run without installing, and they will link with the\nlocally-built library. At install-time these =RPATH= tags will be stripped-away,\nso no extra steps are required when building packages.\n\nThe project build definition file is a plain =Makefile=, so no special syntax\nand rules need to be mentioned here. And because it's a plain =Makefile=, we can\ndefine whatever arbitrary rules we want for anything not specifically covered by\nmrbuild.\n\nFurthermore, again since this is a plain =Makefile=, we can pass it external\noptions in the environment. For instance, if we want to build without\noptimizations, simply invoke\n\n#+BEGIN_EXAMPLE\nCCXXFLAGS=-O0 make\n#+END_EXAMPLE\n\nThe build system will pick up the new build option, and is smart enough to\nreplace the default of =-O3= with the given =-O0=.\n\nNote that this is subtly different from\n\n#+BEGIN_EXAMPLE\nmake CCXXFLAGS=-O0\n#+END_EXAMPLE\n\nThis latter invocation is /not/ supported, and we throw an error if this is\nencountered.\n\n** API\nA complete list of the variables =mrbuild= knows about:\n\n*** Variables that MUST be defined\n\n- =PROJECT_NAME=\n\nThe name of the project. Ends up in the SONAME. Libraries may or may not be\ncalled =lib...=, but the =lib= will be prepended to the SONAME if it's missing.\n\n- =ABI_VERSION=\n\nRequired for libraries. An integer indicating the version of the ABI. Usually\nthe same as the major version number of the project. Together with\n=TAIL_VERSION=, these define the default\n\n#+BEGIN_EXAMPLE\nVERSION ?= $(ABI_VERSION).$(TAIL_VERSION)\n#+END_EXAMPLE\n\nwhich can be used in the per-project =Makefile=\n\n- =TAIL_VERSION=\n\nRequired for libraries. An arbitrary string. Together with =ABI_VERSION=, these\ndefine the default\n\n#+BEGIN_EXAMPLE\nVERSION ?= $(ABI_VERSION).$(TAIL_VERSION)\n#+END_EXAMPLE\n\nwhich can be used in the per-project =Makefile=\n\n- =VERSION=\n\nRequired for non-libraries, optional for libraries. The version string. The\nproject =Makefile= can set this to whatever. If omitted, it defaults to\n\n#+BEGIN_EXAMPLE\nVERSION ?= $(ABI_VERSION).$(TAIL_VERSION)\n#+END_EXAMPLE\n\nIf =VERSION= and =ABI_VERSION= and =TAIL_VERSION= are all defined, the library\nSONAME comes from the ABI and TAIL versions, but the documentation will have the\nVERSION string.\n\nThe compiler gets a preprocessor =#define= that can be used in the sources; this\nis called =MRBUILD_VERSION=. It isn't just =VERSION= to avoid conflicts with\nother symbols the code may be using.\n\n*** Build variables that MAY be defined\n\n- =LIB_SOURCES=\n\nSources to build into a library. If omitted, no library will be built. Wildcards\nare /not/ allowed\n\n- =BIN_SOURCES=\n\nSources to build into executables. By default each executable will be built from\nthe library and each source in =BIN_SOURCES=. So if we have =a.c= and =b.c= in\n=BIN_SOURCES=, then two executables will be built: =a= and =b=, each linking in\nthe library. Wildcards are /not/ allowed\n\n- =CFLAGS=, =CXXFLAGS=, =CCXXFLAGS=, =CPPFLAGS=\n\nFlags for C, C++, both and the preprocessor respectively. By default we pass\n=-O3= and (for C++) =-std=c++0x=. If we specify any other optimization level or\nstandard, the defaults will be omitted. This is commonly used to build without\noptimizations:\n\n#+BEGIN_EXAMPLE\nCCXXFLAGS=-O0 make\n#+END_EXAMPLE\n\nIn the =Makefile= these should be touched with =+== to not override any values\npassed in the environment.\n\n- =LDFLAGS=\n\nSimilar to the above. Contains the linker flags.\n\n- =LDLIBS=\n\nSimilar to the above. Contains the libraries we link with. By default this\napplies to all objects, libraries and executables we build. This is often\noverkill; if we want to apply some linker flag just to a particular object, use\na per-target variable:\n\n#+BEGIN_SRC makefile\nBIN_SOURCES = a.c\na: LDLIBS += -lbleh\n#+END_SRC\n\n*** Installation variables that MAY be defined\n\nThe =DIST_...= variables are only looked-at if we =make install=, which in our\nworld happens only when we're building a package. Generally =make install=\ncopies the files indicated by the =DIST_...= variables to =DESTDIR=.\n\n- =DIST_BIN=\n\nExecutables that we distribute. May include wildcards. If omitted, defaults to\nall the executables that =$(BIN_SOURCES)= produce\n\n- =DIST_INCLUDE=\n\nHeaders that we distribute. May include wildcards. If omitted, no headers are\ndistributed.\n\n- =DIST_BIN_EXCEPT=, =DIST_INCLUDE_EXCEPT=\n\nSimple distribution blacklists. May include wildcards. Anything that is matched\nby =DIST_XXX_EXCEPT= is /not/ distributed, even if it appears in =DIST_XXX=. For\nfancier logic, use the =..._FINDSPEC= variables described below\n\n- =DIST_DOC=\n\nDocumentation we ship. May include wildcards.\n\n- =DIST_MAN=\n\nMan-pages we ship. May include wildcards.\n\n- =DIST_DATA=\n\nArbitrary data we ship. May include wildcards.\n\n- =DIST_PERL_MODULES=\n\nPerl modules\n\n- =DIST_PY2_MODULES=\n\nPython2 modules\n\n- =DIST_PY3_MODULES=\n\nPython3 modules\n\n- =DIST_BIN_EXCEPT_FINDSPEC=, =DIST_INCLUDE_EXCEPT_FINDSPEC=, =DIST_DOC_EXCEPT_FINDSPEC=, =DIST_MAN_EXCEPT_FINDSPEC=, =DIST_DATA_EXCEPT_FINDSPEC=\n\nAfter we install a set of files to the =DESTDIR=, we may want to delete some\nsubset of them. This is similar to the =..._EXCEPT= blacklists above, but\naccomplished with the =find= utility, so we have more flexibility. For instance,\nto install all the manpages except onces for tests, do this:\n\n#+BEGIN_SRC makefile\nDIST_MAN                 := doxygen-doc/man/man3\nDIST_MAN_EXCEPT_FINDSPEC := -type f -name '*_test.3'\n#+END_SRC\n\nTo install only the manpage for the =frobnicator= utility (delete all others) we\ndo this:\n\n#+BEGIN_SRC makefile\nDIST_MAN                 := doxygen-doc/man/man3\nDIST_MAN_EXCEPT_FINDSPEC := -type f \\! \\( -name 'frobnicator.3' \\)\n#+END_SRC\n\n- =EXTRA_CLEAN=\n\nAdditional targets to clean out during a =make clean=\n\n*** QT GUIs\n\nmrbuild has rules to handle QT moc and =.ui= stuff. An executable that uses QT\ncan be defined like this:\n\n#+BEGIN_SRC makefile\nBIN_SOURCES := gui.cc\nMOC_OBJECTS := $(patsubst %.hh,moc_%.o,$(shell grep -l Q_OBJECT *.hh))\ngui: $(MOC_OBJECTS) # gui.o will be linked in automatically\n#+END_SRC\n\n*** Manpages\n\nmrbuild knows how to install manpages, but not how to build them (this is\nusually 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.\n\n*** Python extensions\n\nmrbuild knows how to build python extension modules directly: without\n=distutils= or any such silliness. The result is that all the building is\nhandled by =make=, and everything works the way it's supposed to. This is\ndescribed in detail [[http://notes.secretsauce.net/notes/2017/11/14_python-extension-modules-without-setuptools-or-distutils.html][here]].\n\n** More complex example\nAn annotated example showing some more complex usage appears in\n[[file:build_examples/GNU_Make/Makefile]], and is copied here\n\n#+BEGIN_SRC makefile\n# -*- Makefile -*-\n\nPYTHON_VERSION_FOR_EXTENSIONS := 3\ninclude /usr/include/mrbuild/Makefile.common.header\n\n# This is a sample Makefile using the Makefile.common.header,\n# Makefile.common.footer infrastructure. A quick way to bootstrap a new project\n# is to copy this file to the root directory of the project and then to modify\n# each variable to fit that particular project.\n\n# The name of the project. By convention, libraries should be called lib... but\n# this isn't required\nPROJECT_NAME := libfrobnicator\n\n# The version of the library. We treat the major version as the version of the\n# ABI/API. So every time we change the ABI or an API in a backwards-incompatible\n# way, we bump the ABI_VERSION. If we make non-breaking changes, bumping the\n# TAIL_VERSION is sufficient. In this example, the full version is 0.1\nABI_VERSION  := 0\nTAIL_VERSION := 1\n\n# Build all C and C++ sources in src/ into the library\nLIB_SOURCES := $(wildcard src/*.c*)\n\n# Build all C and C++ sources in bin/ into separate executables\nBIN_SOURCES := $(wildcard bin/*.c*)\n\n# If bin/run_foo.c exists, it is picked up in BIN_SOURCES, and the bin/run_foo\n# executable will be built from the library and bin/run_foo.o (built from\n# bin/run_foo.c). This is the default behavior and nothing needs to be specified\n\n# I specify that bin/run_foo2 consists of the library and bin/run_foo2.o (as\n# usual) AND links with bin/run_foo2_extra.o. The latter will be built from\n# bin/run_foo2_extra.c (or .cc or .cpp and so on, whichever exists)\nbin/run_foo2: bin/run_foo2_extra.o\n\n# Suppose I have bin/run_foo3.c to build bin/run_foo3. And suppose bin/run_foo3\n# needs to additionally build with sources generated from run_foo3.in: the .o\n# links with bin/run_foo3_generated.o (built from bin/run_foo3_generated.c) and\n# the .c #includes run_foo3_generated.h, and that both of these are generated\n# from run_foo3.in. We specify this in the usual way, with a tiny bit of\n# mrbuild-specific stuff:\nrun_foo3:   run_foo3_generated.o\nrun_foo3.o: run_foo3_generated.h\n%3_generated.h %3_generated.c: %3.in\n\tmake_generated_files $\u003c\nEXTRA_CLEAN += run_foo3_generated.h run_foo3_generated.c\n# If we're using gengetopt to generate the sources, the build rule and the\n# EXTRA_CLEAN list above are provided in mrbuild, and can be omitted.\n\n# Any extra flags to pass to the C and C++ compilers. The build system always\n# builds with debugging information and (if no other -O flag is given) with\n# optimization. Use += to not override any settings from the commandline\nCCXXFLAGS += -Wno-unused-parameter\n\n# Extra flags to pass to the C compiler when building src/bleh.o from src/bleh.c\nsrc/bleh.o: CFLAGS += -DFOO\n\n# Link bin/run_foo with -lbar. Do NOT link the library with -lbar.\nbin/run_foo: LDLIBS += -lbar\n\n# Link all the executables AND the library with -lzap\nLDLIBS += -lzap\n\n# If we have doxygen docs, we can state the rule to build them. Everything will\n# be built into doxygen-doc/, the DIST_DOC and DIST_MAN distribution lists below\n# install the man-pages and the html docs\ndoc: doxygen-doc/\ndoxygen-doc/: frobnicator.dox\n\tSRCDIR='.' 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 $\u003c\ndoxygen-doc/%: doxygen-doc/ ;\n.PHONY: doc\nEXTRA_CLEAN += doxygen-doc\n\n# distribute (in a 'make install' and thus into the package) all headers in src/\n# except those that match src/*tst*\nDIST_INCLUDE        := src/*.h\nDIST_INCLUDE_EXCEPT := src/*tst*\n\n# distribute (in a 'make install' and thus into the package) all executables\n# built from BIN_SOURCES except bin/*_tst. And ship the python application\nDIST_BIN := $(filter-out bin/%_tst,$(wildcard $(BIN_TARGETS))) python-tool\n\n# distribute all generated manpages in section 3 EXCEPT those for the test\n# program\nDIST_MAN                 := doxygen-doc/man/man3\nDIST_MAN_EXCEPT_FINDSPEC := -type f -name '*_tst.3'\n\n# distribute the html documentation\nDIST_DOC := doxygen-doc/html\n\n\n# This is the manpage-generating technique from\n# http://notes.secretsauce.net/notes/2018/10/23_manpages-and-readmes.html\n#\n# generate manpages from distributed binaries, and ship them.\nDIST_MAN += $(addsuffix .1,$(DIST_BIN))\n$(DIST_MAN): %.1: %.pod\n\tpod2man --center=\"title: does something\" --name=THING --release=\"thing 0.1\" --section=1 $\u003c $@\n%.pod: %\n\tmake-pod-from-help $\u003c \u003e $@\n\tcat footer.pod \u003e\u003e $@\nEXTRA_CLEAN += $(DIST_MAN) $(patsubst %.1,%.pod,$(DIST_MAN))\n\n# This is the python-extension-generating technique from\n# http://notes.secretsauce.net/notes/2017/11/14_python-extension-modules-without-setuptools-or-distutils.html\nfrobnicator_pywrap.o: CFLAGS += $(PY_MRBUILD_CFLAGS)\nfrobnicator_pywrap.o: $(addsuffix .h,$(wildcard *.docstring))\nfrobnicator/_frobnicator$(PY_EXT_SUFFIX): frobnicator_pywrap.o libfrobnicator.so\n\t$(PY_MRBUILD_LINKER) $(PY_MRBUILD_LDFLAGS) $\u003c -lfrobnicator -o $@\n# The python libraries (compiled ones and ones written in python) all live in\n# frobnicator/\nDIST_PY3_MODULES := frobnicator\nall: frobnicator/_frobnicator$(PY_EXT_SUFFIX)\nEXTRA_CLEAN += frobnicator/*.so\n\n\ninclude /usr/include/mrbuild/Makefile.common.footer\n#+END_SRC\n\n* MAINTAINER\nThis is maintained by Dima Kogan \u003cdima@secretsauce.net\u003e\n* LICENSE AND COPYRIGHT\n\nReleased under an MIT-style license. Modify and distribute as you like\n\nCopyright 2016-2019 California Institute of Technology\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdkogan%2Fmrbuild","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdkogan%2Fmrbuild","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdkogan%2Fmrbuild/lists"}