Solved Building Linux-originating programs could be easier

Hey, everyone.

I've been using FreeBSD daily for a few years now. Probably the
most annoying problem I encounter regularly is the inability to
easily build programs developed under Linux. One understands and
swallows those bitter pills in case of big programs, but when
building even small utilities begins to cause issues, the whole
endeavour becomes disheartening.

Please observe this little case study:
  • Program: clp, a Lua cat with syntax highlighting
  • Source: https://git.sr.ht/~eskin/clp
  • Dependencies:
    • a POSIX compliant operating system,
    • a C99 Compiler,
    • Lua >= 5.1 or LuaJIT,
    • LPEG,
    • luautf8
      $ pkg install lua54 luajit-devel lua54-lpeg lua54-luarocks && luarocks54 install luautf8
  • Problems (sequentially):
    1. The CURDIR variable used in the source Makefile is not respected by FreeBSD make.
      CFLAGS += -I $(CURDIR)/include
      CFLAGS += -I ${.CURDIR}/include
    2. The headers directory needs to be added to the search path and it has to be explicit (-I/usr/local/include won't do). Including a versioned subdirectory cannot be the correct solution.
      CFLAGS += -I $(CURDIR)/include -I/usr/local/include
      CFLAGS += -I ${.CURDIR}/include -I/usr/local/include/lua54
    3. Linker errors for Lua C API (I think) finish off what remains of my good spirit.
      (I tried adding -L/usr/local/lib to FLAGS but I was unsuccessful).
      cc cli.c -pipe -Wall -O2 -ffunction-sections -fdata-sections -Wall -pedantic -I /usr/home/artur/build/clp/include -I/usr/local/include/lua54 -DCLP_PATH=\"/usr/local/share/clp\" -DSRC_LUA_PATH=\"/usr/home/artur/build/clp/lua\" clp.o -o clp
      ld: error: undefined symbol: lua_tolstring
      >>> referenced by clp.c
      >>> clp.o:(bail)
      >>> referenced by clp.c
      >>> clp.o:(print_lua_path)
      >>> referenced by clp.c
      >>> clp.o:(lua_paths_get)
      >>> referenced 3 more times

      ld: error: undefined symbol: lua_getglobal
      >>> referenced by clp.c
      >>> clp.o:(print_lua_path)
      >>> referenced by clp.c
      >>> clp.o:(lua_path_add)
      >>> referenced by clp.c
      >>> clp.o:(lua_paths_get)
      >>> referenced 4 more times
    4. I suspect there are more Makefile incompatibilities or include/linking errors beyond the point of my giving up.

      For the record, here are headers and libraries:
      $ find /usr/local/lib -type f -name '*lua*'
      /usr/local/lib/lua/5.4/lua-utf8.so
      /usr/local/lib/liblua-5.1.a
      /usr/local/lib/liblua-5.3.so
      /usr/local/lib/liblua-5.3.a
      /usr/local/lib/luarocks/rocks-5.4/luautf8/0.1.5-2/luautf8-0.1.5-2.rockspec
      /usr/local/lib/liblua-5.1.so
      /usr/local/lib/liblua-5.4.so
      /usr/local/lib/liblua-5.4.a
      /usr/local/lib/libluajit-5.1.a
      /usr/local/lib/libluajit-5.1.so.2.1.0

      $ find /usr/local/include -type f -name '*lua*'
      /usr/local/include/lua51/lua.h
      /usr/local/include/lua51/lua.hpp
      /usr/local/include/lua51/luaconf.h
      /usr/local/include/lua51/lualib.h
      /usr/local/include/lua53/lua.h
      /usr/local/include/lua53/lua.hpp
      /usr/local/include/lua53/luaconf.h
      /usr/local/include/lua53/lualib.h
      /usr/local/include/lua54/lua.h
      /usr/local/include/lua54/lua.hpp
      /usr/local/include/lua54/luaconf.h
      /usr/local/include/lua54/lualib.h
      /usr/local/include/luajit-2.1/lua.h
      /usr/local/include/luajit-2.1/lua.hpp
      /usr/local/include/luajit-2.1/luaconf.h
      /usr/local/include/luajit-2.1/luajit.h
      /usr/local/include/luajit-2.1/lualib.h



This tiny example is an invitation to grander discussion:

What should we do when we encounter projects that don't build
cleanly on FreeBSD?
If I'm not aware of the specifics of different configure scripts
or build systems or cross-platform differences, can I still
suggest something to a project's developer that could help
resolve the issue?

Specifically:
  1. Are there time- and battle-tested solutions used by port
    maintainers that can be applied with high likelihood of success?
  2. What common steps can be taken to resolve dependencies between
    Linux and FreeBSD, such as different include and lib link
    directories or differences and extensions between GNU Make and
    FreeBSD pmake?
The idea is as follows: if we want to make more software available on FreeBSD, we need a way to resolve this build inferno. To do that, we need acceptable solutions that we can send to project maintainers, who likely have no knowledge or incentive to solve it on their own.
 
Out of personal curiousity, have you heard of FreeBSD Ports? Your issues with the makefile paths are because FreeBSD and Linux put stuff in different places. Always have, probably always will.
The idea is as follows: if we want to make more software available on FreeBSD, we need a way to resolve this build inferno.
This is not a FreeBSD problem. This is upstream or port maintainer issue.
 
You might want to consider using some environment variables to look for includes and libs rather than manually changing all build systems:

https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html#index-CPATH

Also, if one exists; have a quick flick through the ports Makefile to see what flags (or patches) they use and build from there.

Finally, roll up your sleeves and fix things. After a while you get pretty quick at it. I find so much open-source software have build systems that are badly rotten / broken that they even fail to build on many Linux distros.

It is annoying but frankly we have it so much better today than back in the late 90's where Windows "was the only choice". Those were some frustrating ports compared to Linux -> FreeBSD.
 
It would need a makefile and a few other files put into a custom directory. https://docs.freebsd.org/en/books/porters-handbook/ will tell you a lot on how to do this. This will tell you what's needed to build it.

You may need to download ports as well, which is a way of making consistent builds. https://docs.freebsd.org/en/books/handbook/ports/

A lot of information said above is applicable, such as using gnumake, ports and file locations for building. If you're set on making a Makefile to build it, you may want to also go into the IRC channel for freebsd ports.
 
This really mixes several different issues. Let's start with: The best way to build software on/for FreeBSD is always to create a port. But then, what's the best course of actions on issues very much depends on the nature of the issue:
  • If upstream claims portability, but accidentally has "Linuxisms" in the project (this happens surprisingly often!), indeed, report it upstream, best offer a patch fixing it.
  • Regarding issues with Makefiles, only a very small subset of make is actually portable and many upstreams just assume GNU make, so first try building with gmake.
  • CFLAGS, LIBS etc for depedencies should never be hardcoded, different systems install software in different places. pkg-config is a "quasi-standard" for dependencies in C or C++ projects, check whether this can be used (and maybe suggest a patch to upstream for using it). Also have a look at Mk/Uses in the ports tree, there are many helpers available for FreeBSD ports.
  • This list will be incomplete anyways, but: When you need to do changes specifically for FreeBSD and you don't see a way to do them portably and have them "upstreamed", there's always the possibility to add patches locally to your port.
 
Because you should use the make tool the software expected. Ports have “USES = gmake” for just this common requirement of software expecting the GNU version.

(Many of the initial issues listed would be addressed with a single ‘g’.)
My point here is that you don't necessarily need gmake and it shouldn't be your first choice "just because". There are many ports where gmake have been removed in favour of make or never used at all.
 
My point here is that you don't necessarily need gmake and it shouldn't be your first choice "just because". There are many ports where gmake have been removed in favour of make or never used at all.
Ideally, bmake would be used. In this case, gmake was suggested, because of the statement that it was developed on Linux and based on the title. Though, it may not necessarily need Linux/GNU tools to build.

It depends on how the configuration and software is written. On FreeBSD, some programs only build with gmake, as it is at this time.
 
Thanks for all the responses - it cleared a few things up for me. My understanding now is roughly as follows:
  • when installing software that's not available as a port, it would be best to first try making it into one
  • when building, tools like pkg-config or pkgconf can help smoothen include and linking problems
  • when it comes to linuxisms or gnuisms, either bite the bullet (like USES = gmake) or come up with a patch (either for upstream or as part of a port buidling procedure)
Either way, there are no shortcuts and work needs to be done.

Anyhow, I asked a friend for help and it turns out, that in this particular case, all the problems were caused by a bug in the configure script which caused pkgconf to construct erroneous CFLAGS and LFLAGS. It's patched now and builds without hiccups (except for the CURDIR variable).
So, if we encounter something like 'CURDIR' in the upstream Makefile, what do we do? If there are only few such incompatibilities, perhaps a build patch + using bmake is more pragmatic than surrendering to gmake?
 
So, if we encounter something like 'CURDIR' in the upstream Makefile, what do we do? If there are only few such incompatibilities, perhaps a build patch + using bmake is more pragmatic than surrendering to gmake?
Did you read and understand the comments about environment vars in makefiles?

any VAR in a makefile can be overridden by doing VAR=xyz make and unless the Makefile explicitly defines the VAR as
VAR = x

occurances of VAR ?= x in a Makefile will only set the value if it hasn't been passed in from the command line.

re: no shortcuts...true...don't attempt to build or modify makes until you understand build systems.
 
So, if we encounter something like 'CURDIR' in the upstream Makefile, what do we do? If there are only few such incompatibilities, perhaps a build patch + using bmake is more pragmatic than surrendering to gmake?
You're going to maintain your port (either for yourself, or, if you submit it, officially in the tree), so it's ultimately up to you, both ways are possible.

I personally only add patches as a very last resort, simply because they need to be maintained. Regarding GNU make, there's a LOT of software relying on it, so IMHO a USES=gmake doesn't hurt at all.
 
Did you read and understand the comments about environment vars in makefiles?

I think I did. Please notice that this is not about replacing the value of a variable to something else, but about changing the name of the variable that should be expanded by make at build time (from the incompatibile, unexpandable name that FreeBSD's make doesn't recognize, to one that it does). I don't think this is something that can be done by simple env command invocation as you seem to be suggesting.

I personally only add patches as a very last resort, simply because they need to be maintained. Regarding GNU make, there's a LOT of software relying on it, so IMHO a USES=gmake doesn't hurt at all.

I suppose you have a point. This is ultimately a matter of simplicity and convenience.
 
1688567722671.png


😩 I actually had to read a lot of the Porter's Handbook when I wanted to work with the Ports system. I'm not even trying to port any software, just fine-tuning what's already in the Ports system to my needs/preferences. That project is actually on the back burner for me right now, but that's another story.

I do think that OP would benefit from being familiar with the Porter's Handbook... just like we always tell users to be familiar with the regular Handbook... Just my 2 cents for this thread.
 
Thanks to everyone who took time to respond. It was helpful put things into broader perspective. I mark the thread solved.
 
You're right. Small programs which are meant to be portable and POSIX compliant shouldn't use gmake, but many source code programs expect it. By the description, including the title, I thought you were talking about programs which were heavily intended as Linuxisms. Lua isn't Linux/GNU specific either, so it should be able to be built with more kinds of makes regardless of license. There's programs built on Linux, which are meant to be for Unix'es where the only build tool they know is gcc, and that build tool becomes the only expectation.

gmake should be limited to programs which are under GPL, and in some cases LGPL. It's not the case, because gmake use has spread, and everyone thinks that's the only tool, or they think that's a standard tool. People will want to argue, but the build tools in base should be able to compile everything, except which is under GPL, and except which is also meant to be ported to Windows which uses cmake. Of course, cmake is another story, because of its intended use for Windows also.

In some cases, a program says it needs gmake, but by fixing flags by overriding them with their bmake equivalent, it will compile and work with bmake. I don't know how to begin to fix the bigger problem. I'm hardly knowledgeable in shell scripting, and don't know C at all.

NetBSD's version of bmake is meant to be more portable and more compatible than the traditional bmake. If that's used, and is able to compile a lot more programs as is, that would be enough.

I wonder about using the traditional or NetBSD's bmake on top of gcc. What's the point? so that program combination can be exported to Linux, where people compile programs which are under non-GPL licenses, not GNU programs, are meant to be POSIX compliant, or cross portable. devel/bsdowl is interesting as a portable build tool, but I don't know how that works out, and it depends on GraphicsMagick, which has dependencies of its own.

When FreeBSD shifted from GCC to CLANG in base (it was around 2015), Phoronix once had an article that said report any program on FreeBSD which requires gmake to compile it as a bug, because it should compile in bmake. I believe that article was taken down. It was correct in principle, but perhaps bmake wasn't meant for every scenario.
One understands and swallows those bitter pills in case of big programs, but when
building even small utilities begins to cause issues, the whole endeavour becomes disheartening.
For small programs, meant to be cross compatible, that aren't GPL or GNU affiliated or which aren't Linuxisms, this is how I'm feeling. When I can adjust the flags and it builds with bmake, I may need to get an account to report that it compiles under bmake to upstream. It doesn't make sense when gmake and its dependencies are called for, when the programs is close enough that adjusting a few flags can bypass that in-necessity.
you don't necessarily need gmake and it shouldn't be your first choice "just because". There are many ports where gmake have been removed in favour of make or never used at all.
Good to be reminded of that.
 
gmake should be limited to programs which are under GPL, and in some cases LGPL. It's not the case, because gmake use has spread, and everyone thinks that's the only tool, or they think that's a standard tool. People will want to argue, but the build tools in base should be able to compile everything, except which is under GPL, and except which is also meant to be ported to Windows which uses cmake. Of course, cmake is another story, because of its intended use for Windows also.
I'm sorry, but I really have to disagree with everything here. The license is utterly irrelevant in this context. And the same goes for target systems, except maybe for software that only targets one single OS.

In reality, make is the traditional build-tool on *nix systems. But there are several "modern" implementations of it. The portable subset of "make" (working with every implementation, AFAIK that's more or less what was traditionally supported in AT&T's make) is extremely limited. You can use it for simple builds with one or very few modules. Using it to build some complex software is technically possible, but doesn't make any sense, you'll need tons of hand-written rules and dependencies, it will be an unreadable maintenance nightmare.

Now, you have several options:
  • Use an entirely different build system. Of course, you will have new "build dependencies". But OTOH, there are reasons to prefer e.g. cmake or meson (e.g. build performance, more reliable configuration tests, ...), I won't go into details here.
  • Use a tool that generates portable Makefiles. This will also add a build dependency, with one notable exception: The GNU autotools instead generate a POSIX shellscript called "configure" that's distributed with your source and can generate the Makefiles without introducing any extra dependencies. Autotools have their own set of issues though: these huge configure scripts are slooooow ... and as it's all based on macro processing, you can easily mess up and accidentally break portability of both the script and the Makefiles.
  • Decide for one specific implementation of make, so you can use all its features. Then you will have a dependency on exactly this flavor of make. That's what FreeBSD does (building FreeBSD itself as well as the ports tree heavily rely on bmake features, so could never work with gmake). It's also what Linux (the kernel) does, just the other way around, its build system heavily relies on gmake. It's perfectly possible to write maintainable and correct builds using one "modern" implementation of make. But the features you'll need to use are completely incompatible between flavors.
I personally like to have my own software projects rely only on make, but then, as explained, I have to decide which one. Of course, when I write software that is specifically for FreeBSD, opting for bmake is a no-brainer.

For portable software though, I use gmake. And the simple reason is NOT that I like it better than bmake (I don't, both have their pros and cons), the simple reason is, when you have to decide, you pick the one that's easily available on more target systems.
 
Forgot to add a TL;DR: GNU make is *one* viable choice (of many) for the build system you use for some portable software project, and licensing doesn't matter here.

The simple reason licensing doesn't matter: Using a certain tool just to build your software doesn't make it a "derived work" in the sense of the GPL. It won't contain any code of that tool. You certainly can't compare it to e.g. linking a library. In that context, I'd like to add the information that using GNU autotools correctly (so, your distribution will include the "configure" script) WILL include code in your project. But: GNU autotools has a GPL exception specifically for that, so you could still use it for anything, no matter what the license is. I still don't want to use it myself, because IMHO, all this m4 macro processing quickly gets crazy, and, as mentioned before, there's a risk you accidentally break the portability it aims for. This plus the ridiculously long time it takes to execute such a "configure" script. But I have to admit the basic idea behind it is awesome: Distribute source code that does not introduce any extra dependencies just for building it (besides a compiler for the language it uses of course), as long as the target system has some "make" tool and a POSIX/bourne shell.
 
Here is what I did to port this program that may be of interest:
  1. After git cloning I just tried "gmake" (standard thing to try). This failed.
  2. So I then did ./configure and then gmake. Same error as before (luaxlib.h not found)
  3. So then did "locate luaxlib.h" to see if anything had installed it and found a few instances.
  4. Now I tried "gmake CFLAGS+=-I/usr/local/include/lua54" -- this too failed but (optparse.h not found)
  5. locate didn't reveal any optparse.h but it is in the local include/ dir
  6. So I tried "gmake CFLAGS+=-I/usr/local/include/lua54\ -Iinclude" -- ugly but it got me to ld errors.
  7. I tried "gmake CFLAGS+=-I/usr/local/include/lua54\ -Iinclude\ -L/usr/local/lib\ -llua-5.4" and this time the program compiled
  8. But it failed to run (I don't install random 3rd party programs without more checking). Based on error I temporarily did "sudo ln -s $PWD/lua /usr/local/share/lib"
  9. This now failed with lua-utf8 not found. Apparently there is no of lua-utf8 freebsd port
  10. At this point gave up as I got bored + I didn't want to spend more time on this.
Here my goal was to get the program to compile with a minimum number of hacks --- cleanup/port can be done later if the program is worth maintaining (which clp is not, for me). But this is a very typical process. The idea is to make a small change and see how much further you get and repeat. You also learn the peculiarities of FreeBSD (which are there for a reason). I am afraid there is no easy shortcut (unless you train some AI to automate the grunge work) but it is not hard. You can get a hang of this after trying such a few "ports".
 
I was recently successful in putting together an OpenWrt Build System using FreeBSD, which apparently was buildable on FreeBSD at one point, but when I tried it, it wouldn't work, but after taking some time I manged to create a script which builds it effortlessly. It comes with a BSDmakefile consisting of:-

Code:
# SPDX-License-Identifier: GPL-2.0-only
#
# Copyright (C) 2006 OpenWrt.org

world ${.TARGETS}:
        @gmake $@

which simplified things. Out of the box (erm GIT) it almost builds without a problem apart from a minor change which needs to be made to find getopt on FreeBSD. That just amounts to adding a search path.


The only other problem was how to tell the system where to find ncurses.

This was done with

pkg-config=ncurses
I hadn't heard of devel/pkgconf previously and am not exactly sure how it works, but it solved my problem.
 
  1. At this point gave up as I got bored + I didn't want to spend more time on this.
Chances are it wouldn't build perfectly on Linux either.

Some developer's build systems are just unfortunately fragile and broken. Ironically the crap build systems are the hardest aspect of jumping on and getting productive on a new project when working as a contractor. Often much more confusing than the code itself.

The amount of projects I instead just extract the .c, .cpp, .h files from and quickly knock up my own Makefiles is a bit depressing really.
 
I detest configure, autoconf & automake but I still try to use their build system in case I want to send patches back to the developers. As the s/w develops further, I may have to keep sending back patches until the developers get better at writing portable code. In the long term this quite useful as good developers quickly pick up portability tricks & often they continue producing newer programs that I may want to use.
 
Well, one good thing about GNU autoconf is that it makes fully portable Makefiles.
As long as you don't hack something non-portable in your Makefile.am 😏
That's what I meant earlier in this thread, it's unfortunately easy to "mess up" using autotools, although the basic idea certainly is nice!
 
Back
Top