BSD support
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
# Clean: make clean
|
# Clean: make clean
|
||||||
# Install: make install PREFIX=/usr/local
|
# Install: make install PREFIX=/usr/local
|
||||||
|
|
||||||
CC ?= gcc
|
CC ?= cc
|
||||||
CFLAGS ?= -O2 -s -std=c11 -Wall -Wextra
|
CFLAGS ?= -O2 -s -std=c11 -Wall -Wextra
|
||||||
CPPFLAGS += -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE
|
CPPFLAGS += -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE
|
||||||
LDFLAGS ?=
|
LDFLAGS ?=
|
||||||
@@ -12,7 +12,7 @@ LDLIBS += -lpthread
|
|||||||
# The matcher uses POSIX memmem(), which glibc accelerates with SIMD on
|
# The matcher uses POSIX memmem(), which glibc accelerates with SIMD on
|
||||||
# whatever CPU you run on. -mavx2 is harmless but unnecessary; drop it for
|
# whatever CPU you run on. -mavx2 is harmless but unnecessary; drop it for
|
||||||
# maximum portability (e.g. make MARCH="").
|
# maximum portability (e.g. make MARCH="").
|
||||||
MARCH ?= -mavx2
|
MARCH ?=
|
||||||
|
|
||||||
BINARY := gg
|
BINARY := gg
|
||||||
SRC := gg.c
|
SRC := gg.c
|
||||||
|
|||||||
@@ -61,9 +61,28 @@ This produces a single executable named `gg`.
|
|||||||
make MARCH=""
|
make MARCH=""
|
||||||
```
|
```
|
||||||
|
|
||||||
`gg` uses POSIX `memmem()` for matching; glibc (and other libcs) already
|
`gg` uses `memmem()` for matching; glibc (and other libcs) already
|
||||||
accelerate that with SIMD on whatever CPU you run on. The default `-mavx2`
|
accelerate that with SIMD on whatever CPU you run on. The default `-mavx2`
|
||||||
flag is therefore optional and can be dropped for maximum portability.
|
flag was removed from the Makefile because it is x86-only and unnecessary
|
||||||
|
(matching is done by the libc, not by hand-written SIMD), so the default
|
||||||
|
build is already maximally portable.
|
||||||
|
|
||||||
|
- **Building on BSDs and macOS:**
|
||||||
|
|
||||||
|
`gg` builds and runs unchanged on FreeBSD, OpenBSD, NetBSD, DragonFly BSD,
|
||||||
|
and macOS/Darwin — just use the system compiler (`cc`/`clang`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make # CC defaults to cc on systems without gcc
|
||||||
|
# or directly:
|
||||||
|
cc -O2 -std=c11 -Wall -Wextra -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -o gg gg.c -lpthread
|
||||||
|
```
|
||||||
|
|
||||||
|
To keep `gg` portable, the source no longer relies on any single libc's
|
||||||
|
conformance quirks: the `d_type` constants (`DT_DIR`, `DT_REG`, `DT_LNK`,
|
||||||
|
…) have portable fallbacks, `memmem()` is declared/provided where the libc
|
||||||
|
hides it, and the online-CPU count is obtained via `sysconf` on Linux or
|
||||||
|
`sysctlbyname("hw.ncpu")` on the BSDs and macOS.
|
||||||
|
|
||||||
- **Cross-compiling for ARM / other targets:**
|
- **Cross-compiling for ARM / other targets:**
|
||||||
|
|
||||||
@@ -245,8 +264,10 @@ scaled better. `read()` also avoids faulting the entire file into memory.
|
|||||||
|
|
||||||
Yes. The only external links are `libc` and `libpthread`. There are no SIMD
|
Yes. The only external links are `libc` and `libpthread`. There are no SIMD
|
||||||
intrinsics in the source; matching uses `memmem()`, which your libc already
|
intrinsics in the source; matching uses `memmem()`, which your libc already
|
||||||
accelerates with SIMD on the host CPU. It builds and runs on x86-64 and ARM64
|
accelerates with SIMD on the host CPU. It builds and runs unchanged on
|
||||||
alike.
|
x86-64, ARM64, the BSD family (FreeBSD, OpenBSD, NetBSD, DragonFly) and
|
||||||
|
macOS/Darwin — on any POSIX platform with a C11 compiler, `cc`/`gcc`/`clang`,
|
||||||
|
and a `pthread` library.
|
||||||
|
|
||||||
### How fast is it?
|
### How fast is it?
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,71 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* sysctlbyname() is the portable way to query CPU count on every BSD family
|
||||||
|
* (FreeBSD, OpenBSD, NetBSD, DragonFly) and on macOS/Darwin. */
|
||||||
|
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__)
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* On some libc implementations (e.g. FreeBSD) the d_type constants are only
|
||||||
|
* exposed when BSD visibility is enabled. Provide portable fallbacks matching
|
||||||
|
* <sys/dirent.h> so the directory-walk classification always compiles. */
|
||||||
|
#ifndef DT_UNKNOWN
|
||||||
|
#define DT_UNKNOWN 0
|
||||||
|
#define DT_FIFO 1
|
||||||
|
#define DT_CHR 2
|
||||||
|
#define DT_DIR 4
|
||||||
|
#define DT_BLK 6
|
||||||
|
#define DT_REG 8
|
||||||
|
#define DT_LNK 10
|
||||||
|
#define DT_SOCK 12
|
||||||
|
#define DT_WHT 14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* memmem() is a BSD/GNU extension, not POSIX. glibc and the BSD/Darwin libcs
|
||||||
|
* all provide it, but only expose the prototype outside strict conformance
|
||||||
|
* mode, so declare it ourselves when the system has not already. Any libc that
|
||||||
|
* genuinely lacks it (rare) gets a small portable fallback. */
|
||||||
|
#if defined(__GLIBC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__)
|
||||||
|
#ifndef memmem
|
||||||
|
void *memmem(const void *haystack, size_t haystacklen,
|
||||||
|
const void *needle, size_t needlelen);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
static void *gg_memmem(const void *haystack, size_t haystacklen,
|
||||||
|
const void *needle, size_t needlelen) {
|
||||||
|
if (needlelen == 0) return (void *)haystack;
|
||||||
|
if (haystacklen < needlelen) return NULL;
|
||||||
|
const unsigned char *h = (const unsigned char *)haystack;
|
||||||
|
const unsigned char *n = (const unsigned char *)needle;
|
||||||
|
const unsigned char *end = h + haystacklen - needlelen;
|
||||||
|
for (; h <= end; h++)
|
||||||
|
if (memcmp(h, n, needlelen) == 0) return (void *)h;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#define memmem gg_memmem
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Number of online processors, portable across Linux, the BSDs and macOS. */
|
||||||
|
static long gg_nproc(void) {
|
||||||
|
#if defined(_SC_NPROCESSORS_ONLN)
|
||||||
|
long n = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
if (n > 0) return n;
|
||||||
|
#elif defined(_SC_NPROCESSORS_CONF)
|
||||||
|
long n = sysconf(_SC_NPROCESSORS_CONF);
|
||||||
|
if (n > 0) return n;
|
||||||
|
#endif
|
||||||
|
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__)
|
||||||
|
int ncpu = 1;
|
||||||
|
size_t len = sizeof(ncpu);
|
||||||
|
if (sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0) == 0 && ncpu > 0)
|
||||||
|
return (long)ncpu;
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
#define PATH_MAX 4096
|
#define PATH_MAX 4096
|
||||||
#endif
|
#endif
|
||||||
@@ -588,7 +653,7 @@ int main(int argc, char **argv) {
|
|||||||
push_dir(root, "", NULL);
|
push_dir(root, "", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
long nproc = sysconf(_SC_NPROCESSORS_ONLN);
|
long nproc = gg_nproc();
|
||||||
if(nproc < 1)
|
if(nproc < 1)
|
||||||
nproc = 1;
|
nproc = 1;
|
||||||
int nth = (int)nproc;
|
int nth = (int)nproc;
|
||||||
|
|||||||
Reference in New Issue
Block a user