2

If I go into /usr/local/lib, I see a bunch of folders and .dylib files, the dynamically linked library files I'm pretty sure. If I go to /usr/local/include it has a bunch of .h files each of which has the plain C source code uncompiled in it.

If I place a .h file at /usr/local/include/mylib.h, And I have another .c or .h file locally at let's say ~/Desktop/test/foo.c, then inside foo.c I can include mylib.h:

~/Desktop/test/foo.c

#include <mylib.h>

int
main() {
  puts("Hello World");

  return 0;
}

If I follow this, I write this in the terminal:

$ clang -Xlinker -v
@(#)PROGRAM:ld  PROJECT:ld64-351.8
configured to support archs: armv6 armv7 armv7s arm64 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em (tvOS)
Library search paths:
  /usr/lib
  /usr/local/lib
Framework search paths:
  /Library/Frameworks/
  /System/Library/Frameworks/

So /usr/local/lib is in there, which is a bunch of .dylib files. I can't modify /usr/lib.

My question is how I can take a local C library such as ~/Desktop/test/mylib.{c,h}, and integrate it into the install locations of these other C libraries, similar to what homebrew does probably.

I would like to be able to include the library with < angle brackets> instead of "quotes".

So say I have a library mylib.h and mylib.c.

mylib.c

#include "mylib.h"

void
print(char* str) {
  puts(str);
}

mylib.h

#include "stdlib.h"
#include "stdio.h"

extern
void
print(char* str);

Then I have foo.c which includes it.

foo.c:

#include <mylib.h>

int
main() {
  print("Foo");
  return 0;
}

The question is how I compile both mylib and foo.c with Clang such that I can #include <mylib.h> with angle brackets in any project like foo.c.

I have been building them like this:

build:
  @clang -shared -fpic -O2 \
    -install_name mylib.dylib \
    -o mylib.dylib \
    mylib.c
  @clang foo.c build.dylib -o foo
  @./foo
.PHONY: build

It seems to work, but now the question is how to place them programmatically (without XCode) into some appropriate spot to make it work with loading via angle brackets.

Lance
  • 75,200
  • 93
  • 289
  • 503
  • 2
    Why do you want to do that? Resist the temptation, and use `"…"` includes for everything but system headers. There’s *no advantage* to using `<…>` for your own header files. If the actual question is how to set up your own library as a system library then the answer is: use a build system. – Konrad Rudolph Apr 10 '19 at 16:17
  • 1
    Maybe [this](https://stackoverflow.com/questions/21593/what-is-the-difference-between-include-filename-and-include-filename) explains to you the difference between them, but if you really want to use brackets, just do it and pass to your compiler, the directive `-I/path/to/your/headerfile` – Amadeus Apr 10 '19 at 20:01

2 Answers2

5

If you insist:

  • Build the shared library (.dylib) and put it in /usr/local/lib.

  • Copy the header to /usr/local/include.

You'll then be able to link using:

gcc -o program source.c function.c -lmylib

And you'll be able to write #include <mylib.h> in your source code and the header will be found.

On the other hand, it is often regarded as better for project headers to be included using quotes (#include "mylib.h") and you can specify the directories where the headers and libraries are found on the compiler command line (-I/some/where/include for headers; -L/some/where/lib for libraries).

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

I see C projects every now and then, such as this and BareMetalOS (it makes sense for BareMetalOS) where they include there files like #import instead of #import "foo.h".
Wondering how I could get my library to be importable like that.

When projects include project-directory headers using angle brackets, normally what's going on is the build system is adding directories to the compiler's include search path in every time it invokes the compiler (mostly like -I some/project/subdir)

If having a personal "system" directory that gets automatically searched meets your needs, that's the simplest thing. To set that up, the command line options you'd be passing are likely -isystem and your choice of nothing -L, -F, maybe -B, maybe -Wl,-rpath (getting brave now), and ideally not -I (tends to stomp ordering assumptions in build scripts). Unless you're experimenting, don't resort to -isysroot or -resource-dir until it's quite clear how that's called for).

The flags you choose can be an be made implicit adding them to CFLAGS, by invoking clang with a wrapper script (something like eval "clang -my -options ${@}"); or by setting additional search dirs in environment variables LIBRARY_PATH, C_INCLUDE_PATH (for c), CPLUS_INCLUDE_PATH (for c++), and/or CPATH (both) (at least for linux systems; I imagine it respects them on Apple but I'm not certain.)

The truly complete solution is rebuild clang with the search path configured as you'd prefer.

Make sure you're building your dylib with the right link flags, too (doesn't it need --shared?)

l.k
  • 199
  • 8