How to override port Makefile to point to local directory?

Edit: Found a clean solution

---

I am writing software that I would eventually like to install on FreeBSD. I'm currently stuck trying to write a Makefile that will point to my local git dir, so I can build and install it while I'm developing. All of the finished Makefiles reference tar packages, which makes sense. But when I'm actively developing, I don't want to commit the code, push it, have it built, update the makefile with the commit, and make.

Does anyone know of a way to override options to a port's Makefile to point to a local directory on disk? I want to run "sudo make install" and "make package" from my development directory, using the same Makefile that would be in the ports tree.
 
Last edited:
A port Makefile doesn't actually build your software, your software is expected to have its own build system (could be make as well, and if it's FreeBSD-specific, you can make use of the make library in /usr/share/mk, or could be anything else like e.g. cmake/ninja...). The port Makefile automates the whole process of fetching, configuring/building/staging (by calling into the software's build system), and packaging the software.

So, just postpone writing a port. Use whatever build system you like and install your software directly (e.g. make install) while you're developing it.
 
Yes and I want to use poudriere to build and package it... which I believe requires making a port Makefile, correct?
 
Yes. But that's not what you'd do during development. The requirement for a distfile (tarball, the ports framework will also verify a checksum on it) is just one reason. Another one is that a port always does a clean build. During development, you typically only want to build what changed. (I could continue here, ports are expected to install stripped binaries without debugging symbols, another thing you don't want during development, ....)

Just use your own build system until you're happy enough with your software to think about a release and then write a port for it.
 
Yeah I'm definitely missing something here.

fwiw I have already set up a CI pipeline that will build a git commit using poudriere. I just want to speed up the process by not having to commit, push, wait for it to build. I want to build a package locally, and if it all looks good, I'll commit and push.

Use whatever build system you like and install your software directly (e.g. make install) while you're developing it.

I can write a `make install` that just copies the files where I want them... but I don't think I get a `make deinstall` for free, do I? Plus then I'll be duplicating that `make install` in the port Makefile.

My understanding of ports is that I install to ${STAGEDIR}, and then ports can make a package out of it, deinstall it, check for conflicts, etc.

Packaging stuff is new to me. I've never written a `make install` in my life. If it helps, I'm using elixir and building a mix release. I can confirm that my app generally works. The next thing is making sure it works cleanly on FreeBSD - installing things to the right dirs, creating a symlink in /usr/local/bin, etc. I have figured out how to write a Makefile that will build the app using `mix release` and install everything.

I can quickly change my app's code and test it locally. What I can't do is quickly check that the FreeBSD package build works.

I did come up with a script that zips my local dir into the dir & zip structure that ports expects, so at least when ports checks DISTFILES it will get that instead of fetching it from GitHub.
 
I can write a `make install` that just copies the files where I want them... but I don't think I get a `make deinstall` for free, do I? Plus then I'll be duplicating that `make install` in the port Makefile.
No. A port's make stage will call your make install if your own build system is based on make. In that case, your Makefiles are expected to follow the common practice of respecting DESTDIR, the port will set it to the location of the staging dir.

Sure, if you want a make deinstall, you'd have to write it yourself.

Packaging stuff is new to me. I've never written a `make install` in my life.
Uhm, another reason to postpone that IMHO.

Of course, a port Makefile could have its own install recipes. But the preferred way is to just call what upstream provides. So, the build system of your software should provide some way to do an install. And installing in a different directory should be supported. For make, the convention to support this is DESTDIR, for other build systems, it could be different.
 
Sure, if you want a make deinstall, you'd have to write it yourself.

What's the point of that, when ports provides install / package / deinstall functionality?

Uhm, another reason to postpone that IMHO.

Well I want to learn how to do it some time... and now's the time.

Of course, a port Makefile could have its own install recipes. But the preferred way is to just call what upstream provides. So, the build system of your software should provide some way to do an install. And installing in a different directory should be supported. For make, the convention to support this is DESTDIR, for other build systems, it could be different.

Everywhere I've worked, the convention is to build the app, stick it in a dir in a docker container, and have a startup script that calls the known path to the built app. If you want to call that "installing", then sure – but it's a far cry from the cleanliness that FreeBSD's package system provides. In other words, I'd say that we have a solid build system, but are completely lacking an install system.

I'm not trying to make some general purpose `make install` that will run on every OS out there. I want to build my app (using mix release) and then install it to a FreeBSD system. Ports provides a mechanism to do exactly that. Why would I partially re-implement that behavior myself? With ports I can `make install && make deinstall` and end up with my system in exactly the same state, have dependency and conflict checking, etc.

There's a really good chance I'm missing something obvious, but creating a separate install process seems odd to me. I can build my app, I can write a ports Makefile to install the app to FreeBSD... so why not point the Makefile at my working directory vs fetching it from GitHub?
 
What's the point of that, when ports provides install / package / deinstall functionality?
Your own convenience during development for example. Or convenience for the few users of your software that don't use any packaging system. Yes, that's completely optional.

I'm not trying to make some general purpose `make install` that will run on every OS out there.
Well, that's what's typically expected from opensource software source packages. And it's expected to be able to install to a different base dir which is for example used by packaging (by FreeBSD ports, but of course also by lots of package building systems for e.g. Linux).

I repeat myself here: you don't have to use make here, there are other systems (also supported by the ports framework). And again, it's possible to create a port from software that doesn't provide anything for installation. But that's more complex and definitely not the preferred way.
 
I really don't care about writing something that will work out of the box on other systems. My objective is simple: `pkg install myapp` on FreeBSD. That's it. I am building services that are 100% intended to run on FreeBSD. `pkg install myapp`, `service start myapp`, `/usr/local/etc/myapp.d/myapp.conf` etc.

I'll repeat myself here as well: I can build my software, and I can package it with Poudriere. I'd like to bypass the cycle time there. I have it built, and I have a working Makefile for packaging and installing it. I just want to say "get the source from this directory instead of GitHub."
 
If it's specifically for FreeBSD, the make lib in /usr/share/mk (e.g. bsd.prog.mk for program binaries) already provides install targets, no need to write them yourself in that case.

But doing it manually in the port Makefile is discouraged. One reason is the reason you're asking that question in the first place: you can't use a port during development in a sane way. (edit: and repeating what you *want* won't help much, ports are not designed to be used during software development, so what you want just isn't possible. What I'm telling you is the correct way to do it...)

And btw, if it only has to work on FreeBSD, there's nothing to gain in terms of effort. You have to write some rules for installation, be it in your local Makefile or in your port's Makefile. 🤷‍♂️
 
I just want to say "get the source from this directory instead of GitHub."
I understand this as follows: You want to fetch your applications source code, compressed in a file, from a local directory.

You can define that location with the MASTER_SITES variable, followed by the file protocol (file:///) in the Makefile. That protocol is supported by fetch(1).
 
But doing it manually in the port Makefile is discouraged. One reason is the reason you're asking that question in the first place: you can't use a port during development in a sane way. (edit: and repeating what you *want* won't help much, ports are not designed to be used during software development, so what you want just isn't possible. What I'm telling you is the correct way to do it...)

And btw, if it only has to work on FreeBSD, there's nothing to gain in terms of effort. You have to write some rules for installation, be it in your local Makefile or in your port's Makefile. 🤷‍♂️

Okay, I've written a non-port-specific `make install`. Now I want to test the port installer. It still requires a commit-push-update-the-Makefile cycle – the whole part I'm trying to speed up.

However...

I understand this as follows: You want to fetch your applications source code, compressed in a file, from a local directory.

You can define that location with the MASTER_SITES variable, followed by the file protocol (file:///) in the Makefile. That protocol is supported by fetch(1).

This is super helpful. I can zip up my src dir and stick it in the file repo. This is a lot cleaner than sticking a zip in $DISTFILES directly, and working out the dir structure that it expects.

Here's the script that does the job. Thanks!
 
Still the thing is: You don't test a port with every development cycle of your ("upstream") software. And my question remains: why do you want to do that? Your life will be a lot easier if you separate these concerns ;)
 
Still the thing is: You don't test a port with every development cycle of your ("upstream") software. And my question remains: why do you want to do that? Your life will be a lot easier if you separate these concerns ;)
You're right, I don't want to test a port with every development cycle. I want to test the port whenever I make changes to the installation process.

Most of the time, I'm just doing `mix test` and I'm good. But occasionally, I need to do something that uses some aspect of the installation process. That's what want to test without a commit & push cycle.

Which I have now accomplished!

Here's a concrete example for you: I want to configure some aspect of my app with an env var. So I add a call to `System.fetch_env!("MY_APP_FOO")` in my code. I test it out, works great.

Now I need to add that env var to the RC file. I add `MYAPP_FOO` to the RC file.

Without being able to quickly check the installation process, I'll push my code out, then update the Makefile with the new SHA, run it... and find that I have mis-matched the env var names.

I'm not doing my port install after every commit. But when I am working on the FreeBSD installation process, it's helpful to be able to run it against the current version of my source.

I do see the value in having `make install` at the application level, even if it just copies files to $DESTDIR in the exact structure that I want for FreeBSD. So thank you for pointing that out :)
 
I have to admit, rc files are a problem for this clear separation. BTDT. Trying to deliver such a file in your "upstream" tarball is kind of moot, as every system uses some different framework, from dreaded systemd to sysvrc to (awesome!) mewburn rc on FreeBSD 😈

But you'll have to admit this is an edge case :p
 
For anyone else interested in this, I finally came up with a really clean solution:

Bash:
make WRKSRC=$(pwd) USE_GITHUB=no DISTFILES="" -C port

It assumes a really simple USE_GITHUB Makefile (e.g. below).

Here’s the example repo: https://github.com/patmaddox/simple_port_example

Makefile:
PORTNAME= simple-port-example
CATEGORIES= devel
DISTVERSION= 1.0.0
DISTVERSIONPREFIX= v

MAINTAINER= pat@patmaddox.com

USE_GITHUB= yes
GH_ACCOUNT= patmaddox
GH_PROJECT= simple_port_example

.include <bsd.port.mk>
 
Not really. It's not any different from setting any other variable when running make.

USE_GITHUB=yes is for the production makefile.

But when I'm working on it locally, I want to use the local source directory. I do that by specifying WRKSRC. You're not allowed to set WRKSRC with USE_GITHUB=yes, so for local development I override USE_GITHUB=no so it uses the local source instead of fetching from GitHub.
 
Back
Top