12 ms·
Building and Linking Libraries in C
- flukus 10y agoNice simple guide. Perfect for people like me that are "relearning" c.
- drothlis 10y agoYou might also like http://david.rothlis.net/c/compilation_model/ http://david.rothlis.net/c/compilation_model/ -- a tutorial I wrote that goes into some detail on what the preprocessor, compiler, assembler & linker do.
- nothrabannosir 10y agoTangential question: why aren't we using '#pragma once' more? I've adopted it in personal stuff and it's obviously Good. Is anyone still really coding for some arcane compiler that doesn't support it? Or is there some good reason for not just switching?
- Sir_Cmpwn 10y agoIt's not standard. There are more compilers out there than gcc and clang.
- maccard 10y agoWhat compilers don't support it?
- slavik81 10y agoThe Portland Group's compiler (PGI) is the only modern compiler I know of, but there's probably a few embedded system compilers too.
- Sir_Cmpwn 10y agoOne compiler I've encountered is SDCC. But think about new compilers - they shouldn't have to implement non-standard features to compile portable C. #pragma is non-portable.
- nanolith 10y agoThere are proprietary compilers for embedded chipsets that don't support this feature. Granted, these are fewer and further between than they once were, but they are out there. It really depends on how portable you want your code to be. Even though it is widely supported, it still isn't a standard language feature. If your goal is to have a library that runs on most Unix-like and Windows systems, then '#pragma once' works just fine. But, if there's a possibility that your code would be deployed to an odd platform, it's probably best to use traditional header guards. I'm so used to using header guards that the appeal of '#pragma once' isn't that great for me.
- apaprocki 10y agoYou don't have to go that far.. Oracle Studio (nee Sun Studio) for Solaris doesn't support it.
- loeg 10y ago#pragma once is great. I use it in new code. Clang and GCC both support it, don't know about other compilers.
- TheNewAndy 10y ago1 - it isn't obvious what it does (if a file has a symbolic link, then is the link the same file? what about a hard link?) 2 - it offers no performance benefit on sensible compilers (which have a special case in them that can detect the typical header guard pattern and so avoid reading a header twice) 3- it is non standard, and the feature it provides is one which is easily implemented within the standard, where the only disadvantage seems to be that you need to type more characters.
- babuskov 10y agoCan't say about the others, but my IDE just adds #ifndef/#endif automatically, so I don't bother to change it manually. Is there some performance gain from #pragma once ?
- slavik81 10y agoDoes it update automatically when you copy and/or rename files? > Is there some performance gain from #pragma once? No. Include guards can be detected and optimized just the same.
- babuskov 10y ago> Does it update automatically when you copy and/or rename files? IIRC, it does only if I use the Refactor option inside the IDE.
- slavik81 10y agoAn alternative to using LD_LIBRARY_PATH is to bake the rpath into the executable. It's a little nicer for the user, IMO.
- saticmotion 10y agoIncreasingly popular are the "single header libraries", which were popularised by Sean Barrett[0]. It's as simple as downloading the header, putting it somewhere in your tree and #including it where you need it. It's especially useful for redistributing libraries, but I've also found it useful to create these in my own projects. [0]https://github.com/nothings/stb https://github.com/nothings/stb
- wott 10y agoOh, this kind of horror I've met lately has got a name? Well, I learned something today. Thanks ;-)
- stagger87 10y agoYou can copy the functions into a .c file if it makes you feel better.
- saticmotion 10y agoDespite what the code may look like, they all have a very easy to use API. Take stb_image.h for example. Most people need just two functions, stbi_load(), which loads any supported image format to a byte array. And stbi_image_free(), which frees the data. But if you need anything more than that it's all there. e.g. loading from memory, loading via callbacks, support for HDR images, support for custom allocators, preprocessor flags let you exclude code for unused image formats, etc etc
- chj 10y agotruetype font rendering: stb_truetype.h: LOC=3287 Wow. I am speechless. Going to dive in another day.
- flukus 10y agoDoesn't this hurt compile times and increase exe size?
- ndesaulniers 10y ago
- ndesaulniers 10y agoSee also: https://nickdesaulniers.github.io/blog/2016/11/20/static-and-dynamic-libraries/ https://nickdesaulniers.github.io/blog/2016/11/20/static-and...
- peeyek 10y agoI hope there is a tool like Cargo (https://crates.io https://crates.io) in C
- gens 10y agoThere is, your bog standard package manager (in unix and unix-like systems).
- Rusky 10y agoThat sort of package manager has a totally different purpose and does absolutely nothing to help build your code, manage dependency versions, or control how dependencies are built.
- gens 10y agoTotally different ? Are you sure about that ? >.. does absolutely nothing to help build your code .. I don't know much about cargo nor rust. How does it help build your code ? edit: nvm, i found how [0] >.. manage dependency versions .. All package managers do. Granted not implicitly when building your source, as you have to install them yourself. Good libraries can have multiple versions installed at the same time (i won't go into nix and such). >.. control how dependencies are built .. Most (of the used) programming languages don't need to build dependent libraries, they load them dynamically. Note that I don't differentiate between code in headers, code in libraries, or even code in other programs that the specific program would communicate with via some IPC. (side note: i have grown fond of single header libraries, for their simplicity) Also to quote the rust docs "Rust has two distinct terms that relate to the module system: ‘crate’ and ‘module’. A crate is synonymous with a ‘library’ or ‘package’ in other languages." Not 100% what i was saying, but it does hint on how similar cargo is to a "normal" package manager. It seems that everyone wants to build in a package manager these days. Rust, racket, haskell, python... What is wrong with copy-ing code directly ? Do we need these ? It just reminds me of leftpad. [0] http://doc.crates.io/index.html http://doc.crates.io/index.html
- 10y ago
- pdkl95 10y ago> LD_LIBRARY_PATH While this works, it's generally a bad idea to depend on LD_LIBRARY_PATH. This type of environment override should generally be left as a tool for sysadmins and other integration/workaround needs. Instead, you can bake the library search path into the executable with ld's "-rpath" option. gcc -o foo -Wall -Wl,-rpath,/lib/search/dir > -shared Building a shared library may also require building position independent object files. (CFLAGS += -fPIC). If the library is being distributed, it is also a good idea to set the soname[1]. This can get complicated very quickly, so it's probably better to let something like libtool[2] handle building and managing the library. (Autotools is a lot easier[2] to use that its reputation suggests. Way too many configure.ac scripts are a cargo cult mess) [1] http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html#AEN95 http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries... [2] https://autotools.io/libtool/index.html https://autotools.io/libtool/index.html [3] https://autotools.io/whosafraid.html https://autotools.io/whosafraid.html
- Annatar 10y agoBuilding a shared library may also require building position independent object files. (CFLAGS += -fPIC). And -DPIC.
- Keyframe 10y agoon MacOS you can do: install_name_tool -change new_path old_link executable and you can check paths with otool -L executable
- pjc50 10y agoYou can also bake in a relative rpath with $ORIGIN, although the fact that it requires a dollar sign causes endless makefile quoting nightmares: https://enchildfone.wordpress.com/2010/03/23/a-description-of-rpath-origin-ld_library_path-and-portable-linux-binaries/ https://enchildfone.wordpress.com/2010/03/23/a-description-o... This is pretty much the only sensible way to build an executable that statically relies on having a library shipped alongside it.
- tannhaeuser 10y agoI found libtool extremely painful to work with; it will hide your compiled libs in a hidden subdir, will wrap your compiled executable in a fscking shell script that then calls your real binary, it's unable to isolate a build against libs that may or may not be installed on your build system etc. Yet for all magic it does, libtool still doesn't solve the problem of building for a PREFIX (eg. /usr/local) in a temporary directory, and you need a chroot-jail or something for that. From the libtool manual ([1]): Currently it is not generally possible to install into a temporary staging area that contains needed third-party libraries that are not yet visible at their final location. So to build against a shared lib provided by another package, that other package has to be installed at the final destination already. I seriously considered going back to just static libraries at some point. I believe the build system of git does away with autotools alltogether, consisting of just a simple Makefile. Also, a link to phk's libtool rant seems apt here ([2]). [1]: https://www.gnu.org/software/libtool/manual/html_node/Install-mode.html https://www.gnu.org/software/libtool/manual/html_node/Instal... [2]: http://queue.acm.org/detail.cfm?id=2349257&ref=fullrss http://queue.acm.org/detail.cfm?id=2349257&ref=fullrss Edit: typo; make links work
- deleted 10y ago[deleted]
- Annatar 10y agoIf you create your own shared object files and do not install them in /usr/lib, then you need to set your LD_LIBRARY_PATH environment variable so that the runtime linker can find them and load them at run time. A better approach would be to use the $ORIGIN linker keyword (-R works in gcc by special dispensation for compatibility with every other linker in existence, and is portable, as opposed to -rpath): gcc -L/home/newhall/lib -R'$ORIGIN:$ORIGIN/../lib' -lmine -o myprog myprog.c because unfortunately the $ORIGIN keyword includes the $, to embed it effectively into Makefiles and shell scripts, the following is needed in the environment: O='$$O'; export O ORIGIN='$ORIGIN'; export ORIGIN this way, both shell and make will expand $ORIGIN to $ORIGIN, without the need to recursively escape anything. $ORIGIN linker keyword is supported by GNU ld, Solaris / illumos ld, and HP-UX's ld. https://blogs.oracle.com/ali/entry/avoiding_ld_library_path_the https://blogs.oracle.com/ali/entry/avoiding_ld_library_path_... https://blogs.oracle.com/rie/entry/tt_ld_library_path_tt https://blogs.oracle.com/rie/entry/tt_ld_library_path_tt Also, unless one is an operating system vendor, one may not install anything into /usr, as that is the vendor's namespace and having a clash with the vendor could bring one's production down in case of upgrades, were the vendor to deliver the same software. The System V and LSB FHS specifications state that /opt is for 3rd party and unbundled applications, /etc/opt for configuration, and /var/opt for data. Unfortunately, the essay says nothing about library interface versioning with linker map files, for backward compatibility, so that one single shared object library can be used by all versions of the consuming software simultaneously.
- nicolast 10y agoAlso: https://www.akkadia.org/drepper/dsohowto.pdf https://www.akkadia.org/drepper/dsohowto.pdf
- nuclx 10y agodrepper to the rescue
- musicnarcoman 10y ago> (3b) you could also build an ARCHIVE FILE (a statically linked library, libmylib.a) from one or more .o files. If you link with a static library, its code is copied into the a.out file at runtime. Huh? There is no copying at runtime when using a static library. Or have I misunderstood this all these years?
- stefantalpalaru 10y agoDo yourself a favour and use libtool through Autotools: https://autotools.io/libtool/index.html https://autotools.io/libtool/index.html