5

I created a very simple C project and want to build a debian package from it. Manually building the C project via the Makefile works as expected, it build the binary and can be installed in /usr/local/bin. When trying to build a debian packages however it fails with dh_usrlocal: error: debian/myhelloworld/usr/local/bin/myhelloworld is not a directory

The Makefile looks like this:

prefix = /usr/local/bin

all: src/myhelloworld

src/hello: src/myhelloworld.c
    @echo "CFLAGS=$(CFLAGS)" | \
        fold -s -w 70 | \
        sed -e 's/^/# /'
    $(CC) $(CPPFLAGS) $(CFLAGS) $(LDCFLAGS) -o $@ $^

install: src/myhelloworld
    install -D src/myhelloworld \
        $(DESTDIR)$(prefix)/myhelloworld

clean:
    -rm -f src/myhelloworld

distclean: clean

uninstall:
    -rm -f $(DESTDIR)$(prefix)/myhelloworld

.PHONY: all install clean distclean uninstall

The debian directory is created with debmake and i use debuild for building.

The project structure looks like:

.
├── debian
│   ├── changelog
│   ├── control
│   ├── copyright
│   ├── debhelper-build-stamp
│   ├── files
│   ├── myhelloworld
│   │   ├── DEBIAN
│   │   │   ├── control
│   │   │   └── md5sums
│   │   └── usr
│   │       ├── myhelloworld
│   │       └── share
│   │           └── doc
│   │               └── myhelloworld
│   │                   ├── changelog.Debian.gz
│   │                   ├── copyright
│   │                   └── README.Debian
│   ├── myhelloworld.debhelper.log
│   ├── myhelloworld.substvars
│   ├── patches
│   │   └── series
│   ├── README.Debian
│   ├── rules
│   ├── source
│   │   ├── format
│   │   └── local-options
│   └── watch
├── LICENSE
├── Makefile
└── src
    ├── myhelloworld
    └── myhelloworld.c

I have tried to change the default debian/rules file to override the dh_auto_install so it looks like:

%:
    dh $@  

override_dh_auto_install:
    dh_auto_install -- prefix=/usr/local/bin

This fails too. I did check that the binary does exist in debian/myhelloworld/usr/local/bin.

I tried to change the prefix to just /usr/bin. This makes it possible to successfully build the package, but the containing binary is now installed in /usr/bin.

From the error message it seems like debuild expects the myhelloworld to be a directory, but this is the binary. So why is debuild failing on my /usr/local/bin as destination.

Build log:

ep@ep-xps:~/sandbox/myhelloworld-1.0$ debuild 
 dpkg-buildpackage -us -uc -ui
dpkg-buildpackage: info: source package myhelloworld
dpkg-buildpackage: info: source version 1.0-1
dpkg-buildpackage: info: source distribution UNRELEASED
dpkg-buildpackage: info: source changed by Erik <>
 dpkg-source --before-build .
dpkg-buildpackage: info: host architecture amd64
 fakeroot debian/rules clean
dh clean  
   dh_auto_clean
        make -j12 distclean
make[1]: Entering directory '/home/ep/sandbox/myhelloworld-1.0'
rm -f src/myhelloworld
make[1]: Leaving directory '/home/ep/sandbox/myhelloworld-1.0'
   dh_clean
 dpkg-source -b .
dpkg-source: warning: no source format specified in debian/source/format, see dpkg-source(1)
dpkg-source: info: using source format '1.0'
dpkg-source: info: building myhelloworld using existing myhelloworld_1.0.orig.tar.gz
dpkg-source: info: building myhelloworld in myhelloworld_1.0-1.diff.gz
dpkg-source: warning: newly created empty file 'LICENSE' will not be represented in diff
dpkg-source: warning: the diff modifies the following upstream files: 
 Makefile
 src/myhelloworld.c
dpkg-source: info: use the '3.0 (quilt)' format to have separate and documented changes to upstream files, see dpkg-source(1)
dpkg-source: info: building myhelloworld in myhelloworld_1.0-1.dsc
 debian/rules build
dh build  
   dh_update_autotools_config
   dh_autoreconf
   dh_auto_configure
   dh_auto_build
        make -j12 "INSTALL=install --strip-program=true"
make[1]: Entering directory '/home/ep/sandbox/myhelloworld-1.0'
cc -g -O2 -ffile-prefix-map=/home/ep/sandbox/myhelloworld-1.0=. -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro  src/myhelloworld.c   -o src/myhelloworld
make[1]: Leaving directory '/home/ep/sandbox/myhelloworld-1.0'
   dh_auto_test
   create-stamp debian/debhelper-build-stamp
 fakeroot debian/rules binary
dh binary  
   dh_testroot
   dh_prep
   debian/rules override_dh_auto_install
make[1]: Entering directory '/home/ep/sandbox/myhelloworld-1.0'
dh_auto_install -- prefix=/usr/local/bin
        make -j12 install DESTDIR=/home/ep/sandbox/myhelloworld-1.0/debian/myhelloworld AM_UPDATE_INFO_DIR=no "INSTALL=install --strip-program=true" prefix=/usr/local/bin
make[2]: Entering directory '/home/ep/sandbox/myhelloworld-1.0'
install -D src/myhelloworld \
        /home/ep/sandbox/myhelloworld-1.0/debian/myhelloworld/usr/local/bin/myhelloworld
make[2]: Leaving directory '/home/ep/sandbox/myhelloworld-1.0'
make[1]: Leaving directory '/home/ep/sandbox/myhelloworld-1.0'
   dh_installdocs
   dh_installchangelogs
   dh_perl
   dh_usrlocal
dh_usrlocal: error: debian/myhelloworld/usr/local/bin/myhelloworld is not a directory
make: *** [debian/rules:9: binary] Error 25
dpkg-buildpackage: error: fakeroot debian/rules binary subprocess returned exit status 2
debuild: fatal error at line 1182:
dpkg-buildpackage -us -uc -ui failed


0

1 Answer 1

8

Packages aren’t allowed to ship files in /usr/local, only directories, and this is enforced by dh_usrlocal.

The best fix is to follow Debian conventions and install in /usr:

override_dh_auto_install:
        dh_auto_install -- prefix=/usr/bin

If you really want to install to /usr/local/bin, override dh_usrlocal instead:

override_dh_usrlocal:

Note that prefixes are generally understood as the “root” under which the various directories are placed, so you’d have

prefix = /usr/local

…

install: src/myhelloworld
        install -D src/myhelloworld \
            $(DESTDIR)$(prefix)/bin/myhelloworld

This is why your initial attempt installed myhelloworld in /usr: dh_auto_install sets prefix to /usr. If you change your Makefile to the above, you can drop the dh_auto_install override entirely.

(There’s a slight typo in your Makefile, it should be $(LDFLAGS), not $(LDCFLAGS).)

You might find the Debian upstream guide useful.

5
  • 2
    Not exactly sure why i wanted the /usr/local/bin, but override_dh_usrlocal:does the trick in that case. Sticking to the guide lines using /usr/bin seems the best approach after all. Thank you very much for the explanation.
    – Erik
    Feb 29 at 19:48
  • 1
    @Erik Debian policy is that /usr/local is the place for a system administrator to install extra software, without conflicting with Debian packages. That's why /usr/local should be kept free of Debian files.
    – marcelm
    Mar 1 at 10:20
  • If something is against policy, and you're not even sure why you're doing it to begin with, the best course of action is usually to then not do that thing. Mar 1 at 13:05
  • 1
    @Shadur-don't-feed-the-AI with the caveat that policy defines the Debian distribution, so packages which aren’t intended for inclusion in the distribution don’t have to abide by it. However the distribution’s tools can default to policy-compliant behaviour, which is the case here, and it often is easier to follow policy as you say. (I’m not disagreeing with you, just clarifying that policy isn’t applicable to all packages.) Mar 1 at 13:53
  • 1
    @stephenkitt Right. And at that point the maxim "Don't needlessly multiply complications" applies. Mar 1 at 22:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .