Custom Packages: Exporting headers and linking custom packages

Hi all

First of all sorry if this redundant but I have been reading the available documentation and did not find a solution, if anyone has a pointer to the right document, please share and ignore the rest!!!

I am trying to build 2 custom packages (following pretty much the hellowworld documentation guidelines) which are related between them, Package 1 uses Package 2: libraries (.so) and headers. Both packages where compiling and executing correctly until I introduced the dependency, which is a failure on CFLAGS / LDFLAGS.

My questions are:

  • how do I modify CFLAGS / LDFLAGS correctly?
  • Are there environment variables which I may use to point to staging-dir? ( I am assuming this is the right place from where I should be taking .so and headers when using from another package)
  • How do I indicate that the module's headers should go into stagin_dir/target_blabla/usr/include ? I can see that after I compile my module nothin is copied overthere, do I have to indicate it explicitely with something like this?: $(INSTALL_BIN) $(PKG_BUILD_DIR)/myheader.h $(1)/usr/include

Many thanks!!

I made it work, but I am not entirely sure if this was the right approach, therefore I would appreciate if someone more experienced in the matter could add their opinions before closing the topic, thanks!!

"Upper level Makefile"

define Build/Compile
	$(call Build/Compile/Default,EXTRADATA=$(BUILD_DIR))

"Source level Makefile"

LDLIBS += -lpackage2

mytargetbin: mytargetbin.o
	$(CXX) $(EXTRALDFLAGS) -o $@ $^  $(LDLIBS) 

the include in the source was made like this: <package2/package2header.h>

It looks like the wrong approach. Your shared library package Makefile should contain an InstallDev section which installs headers, shared library objects and other support files such as pkg-config recipes into the common staging directory, see e.g.

Your user package should then merely specify DEPENDS:=nameofyourlibsourcepackage .

Additional CFLAGS/LDFLAGS muddling should not be required, just normal #include <libheader.h> and ordinary -l link flags. The common staging directory is automatically searched for includes and linking.

1 Like

Thanks for replying @jow , your approach looks certainly better. However, when trying to apply it, it may seem that I am still missing some stuff which again looks to be related with environment variables and/or missing steps. This is my InstallDev

define Build/InstallDev
	$(INSTALL_DIR) $(1)/usr/include/package1
	$(CP) \
		$(PKG_INSTALL_DIR)/usr/include/*.h \

	$(INSTALL_DIR) $(1)/usr/lib
	$(CP) \
		$(PKG_INSTALL_DIR)/usr/lib/* \

define Package/package1/install
	$(INSTALL_DIR) 	$(1)/bin \
					$(1)/usr/lib \
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ $(1)/usr/lib/
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/binary1  $(1)/bin/
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/*.h 					$(1)/usr/include

A few comments on the above, which may also be related with what might be wrong on what I am doing

  • I dont have a install target on the "source level" makefile (I added an empty one so it does not fail) as I am not sure what is to be expected in there as normally I would copy files similarly to Package/package/install to a "final" destination on a system, but I am not entirely sure where should I copy them on OpenWRT build system, $STAGIN_DIR?
  • I am manually copying the .h files in the install target of the "upper" level makefile, which I am not sure if this is correct, I would think it would make more since on the "source level" but I dont know where to copy them and which environment variables are to be used.

While executing it, the copy command on InstallDev then looks like this:

cp -fpR blabla/openwrt/build_dir/target-x86_64_musl/package1/ipkg-install/usr/include/*.h blabla/openwrt/tmp/stage-package1/usr/include/package1/

While on my system, on that path I have a directory named ipkg-x86_64 instead of ipkg-install

If you had a pointer to a complete example of a package with source (not retrieved remotely) it would be great :slight_smile:

Thanks again for your time!

Depends on your "upper" OpenWrt makefile. If you defined PKG_INSTALL:=1 there, then OpenWrt will invoke the "inner" source level Makefile's "install" target, passing DESTDIR=... as environment variable. The inner source level Makefile is expected to honour $DESTDIR as installation prefix and put its target directory structure beneath it (e.g. $DESTDIR/usr/lib/, $DESTDIR/usr/bin/ etc.). This works for the usual automake build systems but also for "custom" install targets in case they understand $DESTDIR.

If you do not have an install recipe or if it does not understand $DESTDIR then you can simply copy the built artifacts manually out of $(PKG_BUILD_DIR)/... in your upper OpenWrt Makefile's Package/.../install recipe, this is perfectly fine. Make sure to not declare PKG_INSTALL:=1 in your outer OpenWrt Makefile then to avoid it triggering the inner make install.

See above, from your inner, source level Makefile, put those headers into $DESTDIR/usr/include/....

In your "outer" Makefile also make sure to only copy runtime required artifacts (that is, only executables or library objects) within the Package/.../install section since it makes no sense to ship header files and other development resources in the final .ipk packages due to the fact that OpenWrt does not support on-target compilation.

Development related files that are required to compile and link against your library should exclusively be installed from within the Build/InstallDev recipe into the common staging directly.

The installation DESTDIR prefix is set to a temporary directory which is the merged by the build system into the final destination directory and removed afterwards. Since the inner "install" recipe is a black box for OpenWrt, the build system does not know what files and directory are staged by the inner Makefile, so installation is performed into a temporary scratch directory which allows OpenWrt to generate a file manifest before moving the contents to its actual final destination.

Do you mean a self-contained package that is shipping its sources directly along with the OpenWrt Makefile? Here's a few examples for that:

1 Like

Thanks again @jow for your detailed response! Everything starts to make sense now. I made it work by following your guidelines. For the record, in case anyone hits this kind of problem, I am going to write here the things I have corrected since your last comment along with some minor doubts based on differences I have spotted across makefiles:

"Upper Level" makefile:

  • PKG_INSTALL. I removed it, and now I am installing .h files via InstallDev
define Build/InstallDev
	$(INSTALL_DIR) $(1)/usr/include/package1
	$(CP) \
		$(PKG_BUILD_DIR)/*.h \

	$(INSTALL_DIR) $(1)/usr/lib
	$(CP) \
		$(PKG_BUILD_DIR)/* \

My first doubt is regarding the usage of PKG_BUILD_DIR here (this one uses it too: as PKG_INSTALL_DIR was used in your previous example ), which one is the correct/best one? Are both acceptable? Depends on the presense of PKG_INSTALL?

  • Copy error (ipkg-install vs ipkg-x86_64) was gone the moment I removed .h installation from the install target, which now looks like this
define Package/package1/install
	$(INSTALL_DIR) 	$(1)/bin \
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ $(1)/usr/lib/
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/binary1 $(1)/bin/


Again, many thanks for your answers / guidelines! They are much appreciated

Use PKG_INSTALL_DIR when PKG_INSTALL:=1 is in use, it will then refer to the scratch destination directory where the inner source level make install put its resources.

Use PKG_BUILD_DIR when PKG_INSTALL:=1 is not used or when you need to access (private) resources that the inner make install target did not install

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.