Libmacro provides useful C preprocessor macros:
-
ASSERT(...)
takes a series of scalar expressions andassert()
s each one individually. -
NELEM(xs)
evaluates to a constant expression of the number of elements in the array variablexs
. -
ALLOC(Widget, .foo=42, .bar="wow")
provides an easy way to allocate memory with specific values, rather than having to do it in separate steps. -
FREE(...)
takes a series of pointers to allocated memory, andfree()
s each one individually. -
ANY(...)
,ALL(...)
, andNONE(...)
take a series of scalar expressions, and logically evaluate them according to the short-circuiting behavior of&&
and||
. For example,ALL(a, b, c)
will only evaluatea
andb
ifb
is falsy. -
DEBUG("value = %d", x)
provides an easy way to print debugging statements that include the file, line and function they were made on. If you find yourself regularly insertingprintf()
calls to work out what a program is doing, you'll findDEBUG
very handy. -
SLICE(xs, 4, 3)
evalutes toxs[ 4 ], xs[ 5 ], xs[ 6 ]
; it makes it easier to map sections of one array to sections of another (or a struct). -
MIN(1, 2, 3, 4)
gives the minimum value of multiple given expressions, andMAX(12, 34, 56)
gives the maximum value of multiple given expressions. -
CLAMP(x, 2, 42)
returnsx
but lower-bounded by2
and upper-bounded by42
-- ifx == 85
, thisCLAMP
expression will give42
. -
CLAMP_TO_INTMAX(x)
returnsx
as anintmax_t
value, bounded byINTMAX_MIN
andINTMAX_MAX
, and works with unsigned expressions. -
COMPARE(x, y)
returns1
ifx > y
,0
ifx == y
, or-1
ifx < y
.
Read the header files for more documentation on the provided macros. See the tests/
directory for example usage of the macros, and the expected output.
Note that the functions relying on Libpp for dealing with variable arguments (e.g. ASSERT
and ANY
) can only take as many arguments as the limit that Libpp was built with - by default, this limit is 128. The third argument of SLICE
must be less than 128, but this limit can be changed by setting the SLICE_LIMIT
environment variable at build-time.
Libmacro conforms to ISO C11 and ISO C99.
I'll tag the releases according to semantic versioning. All the macros preceded by // @public
, or between // @public begin
and // @public end
, are considered public: they'll only change between major versions. The other macros could change any time. Non-preprocessor identifiers defined in header files are always considered public. New identifiers prefixed with libmacro_
or LIBMACRO_
will not warrant a major version bump.
Every version tag will be signed with my GPG key (fingerprint: 0xD020F814
).
Package.json
specifies the dependencies of Libmacro: where to get them, and what version to use. I've developed a tool called Puck that will parse such a Package.json
, download the specified repositories, check out the specified version, and, if the dependency has its own Package.json
, repeat that process for its dependencies. With puck
on your PATH, in the directory of Libmacro:
$ puck update
$ puck execute build
$ puck execute test
There's nothing magic to what Puck does, so if you would prefer, you can set up the dependencies manually. You just need to have the dependencies in the deps
directory within the Libmacro directory, and have them built (if necessary) before building Libmacro.
Libmacro is available at Bitbucket and GitHub.
Questions, discussion, bug reports and feature requests are welcome at the GitHub issue tracker, or via emails.
To contribute changes, you're welcome to email me patches as per git format-patch
, or to send me a pull request on any of the aforementioned sites. You're also welcome to just send me a link to your remote repository, and I'll merge stuff from that as I want to.
To accept notable contributions, I'll require you to assign your copyright to me. In your email/pull request and commit messages, please insert: "I hereby irrevocably transfer to Malcolm Inglis (http://minglis.id.au) all copyrights, title, and interest, throughout the world, in these contributions to Libmacro". If you can, please sign the email or pull request, ensuring your GPG key is publicly available.
These macros are generic and universally useful, so I don't any need to specify their names as belonging to Libmacro. It would be semantically awkward. The likelihood of name clashes are low anyway; the headers are decoupled so that you can include them individually as you require. Similarly, it should be fairly obvious where each macro came from.
If you really need a different name for an identifier, maintain a fork of the repository and pull updates from this one as you want them.
I don't like unified headers, and I don't want to encourage their use. Unified headers:
- relieve the library developer of their responsibility to provide loosely-coupled modules clearly separated by their purpose and abstraction, and of the user to use those modules as such;
- make it harder to determine where a certain identifier came from;
- make code slower to compile and link.
- pollute the namespace, which can lead to all kinds of nasty bugs;
- make it harder to maintain API and ABI compatibility.
If you need to include six header files from Libmacro, your source file is probably doing too much, and should be broken up.
Copyright 2015 Malcolm Inglis http://minglis.id.au
Libmacro is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Libmacro is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with Libmacro. If not, see https://gnu.org/licenses/.
Contact me for proprietary licensing options.
I believe that nonfree software is harmful, and I don't want to contribute to its development at all. I believe that a free society must necessarily operate on free software. I want to encourage the development of free software, and discourage the development of nonfree software.
The GPL was designed to ensure that the software stays free software; "to ensure that every user has freedom". The GPL's protections may have sufficed in 1990, but they don't in 2014. The GPL doesn't consider users of a web service to be users of the software implementing that server. Thankfully, the AGPL does.
The AGPL ensures that if Libmacro is used to implement a web service, then the entire source code of that web service must be free software. This way, I'm not contributing to nonfree software, whether it's executed locally or provided over a network.