Giter VIP home page Giter VIP logo

pd-lib-builder's Introduction

Makefile.pdlibbuilder

Helper makefile for Pure Data external libraries. Written by Katja Vetter March-June 2015 for the public domain and since then developed as a Pd community project. No warranties. Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's ShakeNMake.

GNU make version >= 3.81 required.

characteristics

  • defines build settings based on autodetected target platform
  • defines rules to build Pd class- or lib executables from C or C++ sources
  • defines rules for libdir installation
  • defines convenience targets for developer and user
  • evaluates implicit dependencies for non-clean builds

basic usage

In your Makefile, define your Pd lib name and class files, and include Makefile.pdlibbuilder at the end of the Makefile. Like so:

  # Makefile for mylib

  lib.name = mylib

  class.sources = myclass1.c myclass2.c

  datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt

  PDLIBBUILDER_DIR=.
  include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder

For files in class.sources it is assumed that class name == source file basename. The default target builds all classes as individual executables with Pd's default extension for the platform. For anything more than the most basic usage, read the documentation sections in Makefile.pdlibbuilder.

paths

Makefile.pdlibbuilder >= v0.4.0 supports pd path variables which can be defined not only as make command argument but also in the environment, to override platform-dependent defaults:

PDDIR: Root directory of 'portable' pd package. When defined, PDINCLUDEDIR and PDBINDIR will be evaluated as $(PDDIR)/src and $(PDDIR)/bin.

PDINCLUDEDIR: Directory where Pd API m_pd.h should be found, and other Pd header files. Overrides the default search path.

PDBINDIR: Directory where pd.dll should be found for linking (Windows only). Overrides the default search path.

PDLIBDIR: Root directory for installation of Pd library directories. Overrides the default install location.

platform detection and predefined variables

Makefile.pdlibbuilder tries to detect architecture and operating system in order to define platform-specific variables. Since v0.6.0 we let the compiler report target platform, rather than taking the build machine as reference. This simplifies cross compilation. The kind of build options that are predefined:

  • optimizations useful for realtime DSP processing
  • options strictly required for the platform
  • options to make the build work accross a range of CPU's and OS versions

The exact choice and definition predefined variables changes over time, as new platforms arrive and older platforms become obsolete. The easiest way to get an overview for your platform is by checking the flags categories in the output of target vars. Variables written in capitals (like CFLAGS) are intentionally exposed as user variables, although technically all makefile variables can be overridden by make command arguments.

specific language versions

Makefile.pdlibbuilder handles C and C++, but can not detect if your code uses features of a specific version (like C99, C++11, C++14 etc.). In such cases your makefile should specify that version as compiler option:

cflags = -std=c++11

Also you may need to be explicit about minimum OSX version. For example, C++11 needs OSX 10.9 or higher:

define forDarwin
  cflags = -mmacosx-version-min=10.9
endef

documentation

This README.md provides only basic information. A large comment section inside Makefile.pdlibbuilder lists and explains the available user variables, default paths, and targets. The internal documentation reflects the exact functionality of the particular version. For suggestions about project maintenance and advanced compilation see tips-tricks.md.

versioning

The project is versioned in MAJOR.MINOR.BUGFIX format (see http://semver.org), and maintained at https://github.com/pure-data/pd-lib-builder. Pd lib developers are invited to regulary check for updates, and to contribute and discuss improvements here. If you really need to distribute a personalized version with your library, rename Makefile.pdlibbuilder to avoid confusion.

examples

The list of projects using pd-lib-builder can be helpful if you are looking for examples, from the simplest use case to more complex implementations.

  • helloworld: traditional illustration of simplest use case
  • pd-windowing: straightforward real world use case of a small library
  • pd-nilwind / pd-cyclone: more elaborate source tree
  • zexy: migrated from autotools to pd-lib-builder

projects using pd-lib-builder

non-exhaustive list

https://github.com/pure-data/helloworld

https://github.com/electrickery/pd-nilwind

https://github.com/electrickery/pd-maxlib

https://github.com/electrickery/pd-sigpack

https://github.com/electrickery/pd-tof

https://github.com/electrickery/pd-windowing

https://github.com/electrickery/pd-smlib

https://github.com/porres/pd-cyclone

https://github.com/porres/pd-else

https://github.com/porres/pd-psycho

https://git.iem.at/pd/comport

https://git.iem.at/pd/hexloader

https://git.iem.at/pd/iemgui

https://git.iem.at/pd/iemguts

https://git.iem.at/pd/iemlib

https://git.iem.at/pd/iemnet

https://git.iem.at/pd/iem_ambi

https://git.iem.at/pd/iem_tab

https://git.iem.at/pd/iem_adaptfilt

https://git.iem.at/pd/iem_roomsim

https://git.iem.at/pd/iem_spec2

https://git.iem.at/pd/mediasettings

https://git.iem.at/pd/zexy

https://git.iem.at/pd-gui/punish

https://github.com/residuum/PuRestJson

https://github.com/libpd/abl_link

https://github.com/wbrent/timbreID

https://github.com/MetaluNet/moonlib

pd-lib-builder's People

Contributors

danomatika avatar katjav avatar umlaeute avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pd-lib-builder's Issues

[Question] How to compile an external in windows.

Not familiar at all with Windows development tools.
On Linux, I know I can just follow the instructions in the Readme of pd-lib-builder and then do make in a terminal and viola!
What is the equivalent in Windows of make? I have installed Visual Studio 2017 and the C++ tools and those are working fine. Do I need Mingw or Cygwin to compile an external?
Also, I' m using Purrr Data, if that makes a difference.
Thanks in advance!

(priority of) standard search path for pd includes

Variable 'pdincludepath' stores a path to pd API headers (m_pd.h etc.) needed for compilation. If not specified as make command argument, the first path found from the following standard list is used:

  1. $(externalsdir)../pd/src
  2. pd include path of an installed Pd-extended package
  3. pd include path of an installed Pd package

This order of priority was determined at the conception of Makefile.pdlibbuilder more than a year ago, facilitating the transition between centralized and decentralized model of lib development.

The search list needs to be reconsidered now. I guess Pd-extended's unmaintained API should removed from the defaults list so no one can build or develop unintentionally against it.

please tag releases

having tagged releases makes it much easier to refer to a given version than a commitish.

LDFLAGS?

how can I add additional linker flags?

e.g. in Debian packages are routinely build with hardening enabled, which involves adding/overriding CPPFLAGS, C(XX)FLAGS and LDFLAGS.

doc not clear

could u give me basic example for creating a Makefile file for compiling the code for Windows.
For example, this is what i wrote for compiling on my Linux system:

lib.name = mylib
class.sources = counter.c
include ../Makefile.pdlibbuilder

what should i write for creating a .dll and not a .pd_linux?

target 'post' forces rebuild of executables

Commit c428456 (following up on pull request #4) introduced targets 'pre' and 'post' to be run before and after target 'all'. Turns out that target 'post' forces rebuild of executables (linking the .o files) even when .o files haven't changed. It was declared as phony target, but even without that it still acts as such, probably because 'post' is not a file so make can't compare timestamps.

While it is not a show stopper, this behavior can be very annoying when developing or bug fixing files in a large collection. Currently I don't see a solution.

interrelated questions around static linking of 'standard libs' with Mingw

Externals built with Mingw need linking with GNU standard libs. If these aren't provided as dlls by Pd (which is the case with vanilla Pd), an external lib must provide its own solution. Pdlibbuilder implements static linking of standard libs by default, with the effect that externals are in this respect equally 'self-supporting' for all platforms. This arrangement leaves a couple of issues though:

  1. libpthread is not included in Mingw standard libs
  2. static linking of standard libs makes externals super bloated
  3. this bloat is not optional

Issue 1 means that externals using pthread are not out of the box equally self-supporting on Windows. This could be solved by treating libpthread as a standard lib in pdlibbuilder.

The importance of issue 2 scales with the number of externals loaded in memory and number of externals distributed in a package. It seems that externals for Windows are roughly 10 times 'too large'. This may be reduced a bit by stripping.

Issue 3 is particularly annoying for monolithic Pd distributions; even when standard libs are provided as dlls, pdlibbuilder will still build those bloated externals. Therefore pdlibbuilder should support an opt-out.

I'm thinking how to solve issue 1 and 3 together, by introducing variables defining statically linked 'standard' libs including libpthread. Something like:


c.standard.static := -static-libgcc -static -lpthread
cxx.standard.static := -static-libgcc -staticlibc++ -static -lpthread

These variables should be evaluated last in the command line for the linker, such that -static will not affect other libs eventually specified. Not sure if this order of options will work. If it works, a central makefile could easily opt out of static standard libs by defining the variables empty in the call to make.

pd.dll: file format not recognized

Hi,

I am trying to compile pd-psycho (https://github.com/porres/pd-psycho) on Windows10 with pd-vanilla (0.49.0) using pd-lib-builder but I keep encountering error messages that I don't really understand.

I am using MinGW to be able to use the "make" command under Windows.
However, as soon as I use "make" in the pd-psycho folder, it returns this error :
69371075_399392444022904_2478048670679826432_n

Since I explicitely refered to C:/Pd/bin, I can't understand why the command returns "C:/Pd/bin/pd.dll: file not recognized: file format not recognized".

Do someone have an idea on how to fix this please ? What am I doing wrong ?

Thanks by advance

Add a subdir with tests / examples to the project

In my local pdlibbuilder repo I have untracked source files for the purpose of testing. They are organized in 4 small libs to test various kinds of builds:

  • single-class executables
  • multi-class executable
  • multiple-source-file single-class executable (C++)
  • single-class executables + shared lib

Although this set covers much of pdlibbuilder's functionality, it is not a systematical test approach since it isn't part of the distribution. The classes are copied from my personal pd projects so it makes no sense to include them with pdlibbuilder.

Ideally pdlibbuilder should have specially designed test libs or objects which could not only serve for regression testing but also as examples that illustrate pdlibbuilder features. Also a part of it could integrate with the externals tutorial (http://pdstatic.iem.at/externals-HOWTO/). Then we could get rid of the puredata/helloworld repository with its discouraging submodule.

arch.cflags on causes FTBFS on armel

just to let you know: the automatic optimization flags for armv7l (namely: -mfloat-abi=hard) are causing build-failures on Debian's armel architecture.

 $ uname -a
 Linux abel 3.16.0-4-armmp-lpae #1 SMP Debian 3.16.7-ckt20-1+deb8u3 (2016-01-17) armv7l GNU/Linux

Here is a build-log for pd-cyclone (0.2~beta1), as maintained by @electrickery (which does not yet use the newest Makefile.pdlibbuilder)

removing any arch-flags as in the following invokation fixes the problem, so it is not a big problem.

 make arch.fags=""

OSX fat binaries, default or not?

Currently Makefile.pdlibbuilder builds fat binaries by default. This is not good practice but it follows from the fact that many people still use 32 bit Pd while being on 64 bit OSX. Some Pd libs, notably GEM, aren't ready for OSX 64 bit yet.

In the context of deken packages the fat binary default is helpful for the moment. But in the context of a centralized build system like pdl2ork and purr-data, it is not. There should at least be an easy method to override the default, from command line but also from a central makefile.

But I would like to change default build to native architecture. With commit e8a3a48 on branch optional fat, the variable to define target architecture is called 'arch' and 'fat' is equivalent for 'i386 x86_64'. The arch variable is in fact a cross compilation convenience variable and I'm planning to expand its use for other cross compilation purposes too.

shared.ldflags broken when building with helper-library

now that we have a simple test-suite it starts to catch errors :-)

using the shared.ldflags variable fails to expand the shared.lib variable.

Building the tests/multishared/ project I get:

$ make -C tests/multishared
make: Entering directory '<<pd-lib-builder>>/tests/multishared'
++++ info: using Makefile.pdlibbuilder version 0.6.0
++++ info: using Pd API /usr/include/pd/m_pd.h
++++ info: making target all in lib multishared
++++ info: making shared.o in lib multishared
cc -DPD -I "/usr/include/pd" -DUNIX  -fPIC  -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing -O3 -ffast-math -funroll-loops -fomit-frame-pointer -march=core2 -mfpmath=sse -msse -msse2 -msse3 -o shared.o -c shared.c
++++ info: linking objects in shared lib libmultishared.pd_linux.so
cc -rdynamic -fPIC -shared -Wl,-soname,  -o libmultishared.pd_linux.so shared.o -lc -lm
/usr/bin/ld: SONAME must not be empty string; ignored
++++ info: making multisharedB.o in lib multishared
cc -DPD -I "/usr/include/pd" -DUNIX  -fPIC  -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing -O3 -ffast-math -funroll-loops -fomit-frame-pointer -march=core2 -mfpmath=sse -msse -msse2 -msse3 -o multisharedB.o -c multisharedB.c
++++ info: linking objects in multisharedB.pd_linux for lib multishared
cc -rdynamic -shared -fPIC -Wl,-rpath,"\$ORIGIN",--enable-new-dtags    -o multisharedB.pd_linux multisharedB.o  -lc -lm   libmultishared.pd_linux.so
++++ info: making multisharedA.o in lib multishared
cc -DPD -I "/usr/include/pd" -DUNIX  -fPIC  -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing -O3 -ffast-math -funroll-loops -fomit-frame-pointer -march=core2 -mfpmath=sse -msse -msse2 -msse3 -o multisharedA.o -c multisharedA.c
++++ info: linking objects in multisharedA.pd_linux for lib multishared
cc -rdynamic -shared -fPIC -Wl,-rpath,"\$ORIGIN",--enable-new-dtags    -o multisharedA.pd_linux multisharedA.o  -lc -lm   libmultishared.pd_linux.so
++++info: target all in lib multishared completed
make: Leaving directory '<<pd-lib-builder>>/tests/multishared'
$

note the lines:

cc -rdynamic -fPIC -shared -Wl,-soname,  -o libmultishared.pd_linux.so shared.o -lc -lm
/usr/bin/ld: SONAME must not be empty string; ignored

my compiler (gcc-9.2.1) is quite forgiving, so the test actually succeeds.
however, on other systems (notably an android test-build), the -Wl,-soname, flag (without an actual SONAME) raises an error (that's how i discovered it).

Running git bisect I see that this was introduced with a6975e9 (reordering makefile sections)

datafiles with special characters ($)

while converting a project to the pd-lib-builder Makefile I ran into the following problem:

one (well, two) of datafiles contains a $ in the filename (yes, ugly; but cannot be helped now).
unfortunately this makes make install bail out with an error:

$ find abs/ -name "*.pd"
abs/$args-help.pd

$ cat Makefile
# ...
datafiles = $(wildcard abs/*.pd)
#...

$ make install DESTDIR=/tmp/bla
...
install: cannot stat 'abs/-help.pd': No such file or directory
Makefile.pdlibbuilder:1017: recipe for target 'install-datafiles' failed
make: *** [install-datafiles] Error 1

$ 

is there any way to support such awkward filenames?

out of tree builds?

is it possible to build out-of-sourcetree builds (that is: running the build from a directory different from where the Makefile is)?

this can be very handy when building for multiple configurations (architectures, optimization,...)

arch.flags vs CFLAGS

i just noticed that arch.flags will prevail even when i pass CFLAGS to the build:

 $ make CFLAGS="-g -O2"

will still contain -march=core2 -mfpmath=sse -msse -msse2, which is contrary to what i would expect, as these architecture specific flags are not strictly needed to produce a valid build (and i would argue that they are rather optimization flags).

I understand that it is easy to add another arch.flags="" to make call to make, but i think the current behaviour does not follow POLA.

detect target platform consistently, and simplify cross compilation

Experimental branch target-detection has a series of commits (starting with 1dc4219b) to implement consistent target platform detection (hardware architecture and OS). It is based on target triplet as reported by compiler with option -dumpmachine. This option was first suggested by @umlaute in the context of issue #37, to detect architectures in the case of Windows.

The jungle of GNU triplets scared me initially (some are even quadruplets), but of course pdlibbuilder supports only a small subset of them. For our purposes, the only distinction that triplets can't make is between armv6 and armv7 (both arm-linux-gnueabihf). For armv6 (first gen RPi, RPi Zero) I stayed with autodetection in native compilation only, and it must be explicited otherwise.

Commit 262143b introduces an optional user variable PLATFORM to hold a target triplet which is parsed as the base name for tools required for the build (preprocessor, compilers and strip). If the tool chain is available in the path, no other variables need to be overriden for cross compilation. It is the equivalent of autotools' --host parameter.

Using variable PLATFORM I could cross-compile for Linux (Intel and ARM), OSX and Windows, on a single Linux 64 bit machine with cross tool chains installed for all those platforms. Native compilation must be tested as well to make sure no regressions are introduced. I have no access to the following platforms: OSX > 10.8, Windows 64 and 32 bit. @Lucarda, @danomatika, could you give branch target-detection a try?

Oh I almost forgot to mention: fat-binary-default for OSX was sacrified in the process. It felt so stupid to poll the compiler for its target architecture and still add another architecture. See commit 65e9fc7 for a user-friendly alternative to get fat builds.

variable for alternative extensions

Pd externals for Linux have extension 'pd_linux' by default but Pd also knows a couple of architecture specific Linux extensions: 'l_i386', 'l_ia64' and 'l_arm'. This is useful for 'fat library' distributions (because you can't easily make fat binaries for Linux). For convenience Makefile.pdlibbuilder could build with an appropriate alternative extension if a user specifies a certain variable, like use-alternative-extension=yes.

honor pkg-config for pd

Pd provides a pkg-config script, which could be utilized to guess the correct flags

$ pkg-config --cflags pd
-DPD -I/usr/include/pd
$ pkg-config --libs pd
$

Makefile.pdlibbuilder ignores PDBINDIR

When having PD installed in none of the Windows "obvious" places (e.g. Program Files or %AppData%...etc), the Makefile's script seems to ignore the user-specified PDBINDIR when it creates the linker line that pulls in pd.dll. From the Makefile (Makefile.pdlibbuilder):

"shared.ldflags = -static-libgcc -shared "$(pdbinpath)/pd.dll"

...where it uses the 'pdbinpath' var instead...which is earlier detected with this:
"

ifeq ($(system), Windows)
pkglibdir := $(APPDATA)/Pd
ifndef pdbinpath
pdbinpath := $(shell ls -d "$(PROGRAMFILES)/pd/bin")
endif
ifndef pdincludepath
pdincludepath := $(shell ls -d "$(PROGRAMFILES)/pd/src")
endif
endif
"

...which apparently takes no regard to what PDBINDIR has specified.

RESULT: the linker tries to use "/pd.dll" (since it obviously didn't find my pd's "bin" dir in any of the obvious places) and fails

WORKAROUND/HACK:
towards the top of the Makefile.pdlibbuilder, hardcode like so:
pdbinpath = $(PDBINDIR)

(This is obviously bad but it shows that this is in fact the problem, as the linking will succeed with this modification)
(For reference, my Pure Data is installed in "c:\standalone_apps\pd-0.49-0")

Target architecture detection for MinGW 32 and 64

Pdlibbuilder has a crude form of automatic platform detection (OS and architecture, this issue is about the latter). Native architecture is found from uname -m, and architecture-dependent build settings are made in the assumption that the target architecture is the same.

Now that @Lucarda is paving the way towards 64 bit Windows for Pd and externals, it turns out that native architecture detection makes no sense for Mingw-w64. We need to query the compiler for architecture as @umlaeute has clarified, since Mingw-w64 can build for 32 and 64 bit Windows on 'any' architecture. It is inherently a form of cross compiling. See issue #37 that sparked the discussion. This new issue is opened because the subject went far beyond the original issue.

In short, we need two methods for architecture detection (native and target). Native architecture was always detected by pdlibbuilder with:

machine := $(shell uname -m)

where -m is short for --machine

For target architecture, the compiler can be queried with argument -dumpmachine (suggested by @umlaeute). The report comes in the form:

<cpu>-<vendor>-<os>

See https://www.gnu.org/software/autoconf/manual/autoconf-2.65/html_node/Specifying-Target-Triplets.html for info about target triplets. The first field (cpu) must be extracted. It may happen that one compiler (C or C++) is user-specified for cross-compilation and the other not, so both must be queried and a user-defined compiler must have precedence over a default compiler to find the intended target architecture.

For the moment at least, target architecture detection would be used for MinGW / MSYS only, where the choice is between compilers for 32 and 64 bit Intel / AMD. It would be nice to apply it for all platforms, but they are too diverse for a uniform solution so this must go step by step if possible at all. Anyway for MinGW it is now most important.

I'll summarize some implementation suggestions from the discussion in issue #37 later, if still relevant.

[WIP]--Windows paths “pd/bin” and “pd/src”

This data comes from various make allvars:

Showing what "$(PROGRAMFILES)/pd/bin") and "$(PROGRAMFILES)/pd/src") get:

Msys1 (win8.1)

Lucarda@T410 /c/KatjaV/rawCfiles
$ make allvars
ls: C:\Program Files (x86)/pd/bin: No such file or directory
ls: C:\Program Files (x86)/pd/src: No such file or directory

...

variable (environment) PROGRAMDATA = C:\ProgramData
variable (environment) PROGRAMFILES = C:\Program Files (x86)
variable (environment) PROGRAMFILES(X86) = C:\Program Files (x86)
variable (environment) PROGRAMW6432 = C:\Program Files

Msys2 (win8.1)

Lucarda@T410 MINGW32 /c/KatjaV/rawCfiles
$ make allvars
ls: cannot access 'C:\Program Files/pd/bin': No such file or directory
ls: cannot access 'C:\Program Files/pd/src': No such file or directory

.....

variable (environment) PROGRAMFILES = C:\Program Files
variable (environment) ProgramData = C:\ProgramData
variable (environment) ProgramFiles(x86) = C:\Program Files (x86)
variable (environment) ProgramW6432 = C:\Program Files

Msys2 (win10)

Lucarda@win10exthd MINGW32 /g/win10onexthd/KatjaV/rawCfiles
$ make allvars
ls: cannot access 'C:\Program Files/pd/bin': No such file or directory
ls: cannot access 'C:\Program Files/pd/src': No such file or directory

....

variable (environment) PROGRAMFILES = C:\Program Files
variable (environment) ProgramData = C:\ProgramData
variable (environment) ProgramFiles(x86) = C:\Program Files (x86)
variable (environment) ProgramW6432 = C:\Program Files

Msys2 (win10)

Lucarda@win10exthd MINGW64 /g/win10onexthd/KatjaV/rawCfiles
$ make allvars
ls: cannot access 'C:\Program Files/pd/bin': No such file or directory
ls: cannot access 'C:\Program Files/pd/src': No such file or directory

...

variable (environment) PROGRAMFILES = C:\Program Files
variable (environment) ProgramData = C:\ProgramData
variable (environment) ProgramFiles(x86) = C:\Program Files (x86)
variable (environment) ProgramW6432 = C:\Program Files

Here some usefull information. The nsi-installer script:

https://github.com/pure-data/pure-data/blob/master/msw/build-nsi.sh

no uniform naming scheme for important variables ('PD_PATH', 'objectsdir')

Variable names in makefiles should be consistent and intuitive, in particular those which are meant to be used as make command arguments. Unfortunately, a few important Makefile.pdlibbuilder variables are inconsistent in various ways. Consider 'PD_PATH' and 'objectsdir', variables to hold a path to a directory. They are passed as arguments from pd-extended's central makefile to lib makefiles, and 'inherited' by Makefile.pdlibbuilder for compatibility. But the variable names are hard to memorize because:

  1. - one is upper case, the other lower case
  2. - one has an underscore, the other not
  3. - one speaks about path, the other about directory

Regarding upper / lower case, these are the general guidelines I try to follow:

  • upper case for standard flag categories (like CFLAGS) and utilities (like CC), plus DESTDIR
  • lower case for variables defined by the makefile(s)

See https://www.gnu.org/software/make/manual/html_node/Makefile-Conventions.html. A makefile must honour CFLAGS, CC, DESTDIR etcetera, but not define them or at least allow them to be overridden from the environment because people expect that. Variables for paths (like 'prefix' and 'libdir'), should be in lower case and defined by the makefile. DESTDIR is an exception, a path component used for staged install.

Our variable 'objectsdir' defines a path to the root directory of installed pd libs and is an alias for 'pkglibdir', which in turn is a conventional name. Although 'objectsdir' is unfortunately not an apt name for a directory with libraries, at least it follows the lower case convention.

Variable PD_PATH in pd-extended's central makefile defines the path to the pd root dir inside the centralized build system. The Makefile Template has platform dependent PD_PATH definitions. Why uppercase? The Makefile Template has upper case for most (but not all) makefile-defined variables, I can't see a rule behind it.

What about the path / dir distinction? A path is a trajectory in the file system, leading to a directory or file. The meaning of 'directory' is ambiguous. It is often used to denote 'folder', more highlighting the content aspect than the trajectory aspect. Therefore I liked 'path' better initially, and implemented variables 'pdincludepath' and 'pdbinpath' analogous to 'PD_PATH' but leaving away the upper case and underscore. In retrospect I regret my choice for 'path'. Canonical names like 'includedir' and 'libdir' all specify directories with the meaning of paths, not folders. I should better have followed makefile conventions than etymological considerations. Then we could have had a coherent variable set like this:

  • pddir: path to pd root dir
  • pdincludedir: path to pd includes dir (where the pd API files are)
  • pdbindir: path to pd binary dir (where the pd executable is)
  • pdlibdir: path to pd libraries root dir

Much easier to memorize. 'PD_PATH' and 'objectsdir' could have been implemented as aliases. But... aliases are still possible of course.

confusing documentation about cross-compilation

The tips-and-tricks starts with a chapter "cross-compiling on linux x86_64 for other platforms":

## cross-compiling on linux x86_64 for other platforms

why does it say "linux x86_64"? the cross-build toolchains are independent of the host. e.g. (in Debian) there are "i686-linux-gnu" packages available for the arm64 architecture, and afaics you can install mingw on your raspberry.

i suggest to just drop the architecture specifier and call it "cross-compiling on linux for other platforms and architectures"

multiple arch builds incompatible with dependency checking

Currently Makefile.pdlibbuilder makes fat binaries by default on OSX. A non clean build attempt on OSX (10.5 at least) triggers gcc error because some preprocessor flags are not allowed for multiple architecture builds, amongst them flag -MM which is used for dependency checking.

I don't want to remove dependency checking or disable it by default. Developers expect a build system to do dependency checking and it would be confusing if you need to enable it explicitly.

Alternatively we could build single architecture by default and introduce a make option to build fat binaries.

for{Linux,Windows,Darwin} should not use uname

to use OS-specific sets, pd-lib-builder provides the for* mechanism

ifdef forWindows
   ldflags += -lws2_32
endef

unfortunately, this doesn't work when cross-compiling (manually adding system=Windows), because the for* defines are evaluated based on the output of uname.

instead i think the for* variants should be expanded based on the value of system.

[WIP] --How to handle Windows 32 and 64 bit externals

Extracted from @umlaeute @ #38 :

that problem only exists if somebody wants to use both 32bit and 64bit Pds on the same machine.

in theory Pd already has a mechanism to care for this: use a different filename extension for each platform/architecture. e.g. on linux we use .pd_linux instead of the (more standard) .so.

on w32 we could already use .m_i386 instead of the (more standard) .dll. so far nobody has adopted to this. also there currently isn't a .m_amd64 searched for on w64.

so, i think:

  • W32 32bit externals should use the .m_i386 extension instead of .dll
  • Pd ought to support the .m_amd64 extension for w64
    • for now "W32 64bit" (W64) externals should use .dll as the extension

that's probably a much better scheme than using different paths for different architectures, as it allows a single deken-external to contain multiple architectures.

Suggestion to add “-static” for windows (64-bit Pd is coming and all externals needs recompilation: they are all 32-bit)

As the windows 64-bit Pd is coming I suggest to include “-static” in the following lines:

line 581 c.ldflags = -static -static-libgcc -shared \

line 589 shared.ldflags = -static -static-libgcc -shared "$(pdbinpath)/pd.dll"

I have tested compilation for w32 with these lines added and externals worked without the need to ship dependencies.

As an example here is https://github.com/porres/pd-cyclone [coll]. Download pkg below:

static-flag-tests.zip

The above pkg has different compilations. To test functionality close and reopen Pd on each test. (you can open ”coll-help.pd“ ::: make sure you don’t have another ”Cyclone“ somewhere in your path.)

[coll] is one case (as many others) that uses pthread and adding the “-static” flag nulls the need to ship pthread implementation.

Any thought against the “-static” flag?

allow 'cflags' on all levels (class, classes, common, shared)

It would be nice if 'cflags' can be defined on every level in addition to the global 'cflags':

  • <classname>.class.cflags (applies to all sources for the given Pd class)
  • common.cflags (applies to the static library)
  • shared.cflags (applies to the shared library)

For an easy way to set the cflags for a single object file, see #65 (comment))

Use cases:

  • control compile time configurations (debug levels, default values, enable/disable features)
  • DLL export/import macros
  • pass different language specific compiler options (C vs. C++)
  • ...

pdbinpath vs PDBINDIR on w32 builds

it seems that (with 872c34b) the PDBINDIR var is not honoured. instead the pdbinpath is used. shouldn't it be the other way around if PDDIR is set?

$ export CC=gcc
$ mingw32-make PDDIR="Pd"
gcc -DPD -I "C:\projects\libdir./Pd/src" -DMSW -DNT   -DVERSION='"1.11"' -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing -O3 -ffast-math -funroll-loops -fomit-frame-pointer -march=pentium4 -msse -msse2 -mfpmath=sse -o foo.o -c foo.c
++++ info: linking objects in foo.dll for lib foo
gcc -static-libgcc -shared -Wl,--enable-auto-import "/pd.dll"    -o foo.dll foo.o
gcc.exe: error: C:/Program Files/Git/pd.dll: No such file or directory
Makefile.pdlibbuilder:796: recipe for target 'foo.dll' failed
mingw32-make: *** [foo.dll] Error 1

-fpic vs -fPIC

I recently stumbled across a build-failure due to the use of -fpic in the pd-lib-builder.

This was on a not-so-common architecture (s390x).
The full failing build-log can be found here.

Replacing -fpic with -fPIC (upper-case) fixed the problem (replacing the compiler-flags was enough, btw)

So i wonder: why is pd-lib-builder using -fpic instead of -fPIC in the first place? (it seems that the latter is far more widespread).

using $(lib.version) in cflags

i would like to pass the automatic variable $(lib.version) as a preprocessor define to the compiler.
So i added the following to my Makefile:

 cflags = -DMY_VERSION=$(lib.version)

and test it with:

 $ make vars | grep cflags
 variable cflags = -DMY_VERSION=0.1.2

so far so good (0.1.2 being the version as defined in my meta-patch)
unfortunately, during the actual build the $(lib.version) is not expanded:

 $ make
 [...]
 cc -DUNIX -DPD -I "/usr/include/pd/" -fpic -DMY_VERSION= -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing -O3 -ffast-math -funroll-loops -fomit-frame-pointer -march=core2 -mfpmath=sse -msse -msse2 -msse3  -o foo.o -c foo.c
 [...]

since i'm notoriously bad with make's variable expansion, I'm stuck...

Target 'install-strip' breaks unilinear chain of rules

Target install-strip was introduced as a response to extremely bloated executables from Mingw-w64, as an outcome of discussion in issue #42. Size reduction after stripping doesn't normally outweigh the reduction of options for troubleshooting, but that is different with Mingw-w64 where non-stripped sizes are up to 10 times larger, no matter if built with static standard lib or not.

With target install-strip as an alternative to regular install which doesn't strip, stripping appears to be optional, a choice up to anyone who builds. But that is no longer the case when for example:

  1. a library makefile defines install as prerequisite of a custom target, or
  2. a library makefile calls make install as a submake process in a custom target, or
  3. a central makefile in a multi-lib project calls make install

Think of test targets or special packaging targets in a lib makefile. Considering such use cases, 'parallel' installation targets aren't a good solution to provide optional stripping. In general a chain of make rules should be unilinear, but install-strip formally and effectively introduces a diverging build route rather than an extra option on a given route. This is not justified since stripped and non-stripped executables are supposed to be identical regarding their functionality.

A variable instead of alternative target could keep the chain of rules in pdlibbuilder unilinear from source files to installed executables, so lib makefiles and project makefiles can rely on that. Stripping could be done like:

make install strip=yes

with a strip 'function' (multiline define) which does nothing by default and only strips when strip=yes, in target install-executables.

why no variable 'pdpath'?

The Makefile Template of pd-extended defines variable 'PD_PATH', from where 'PD_INCLUDE' (for pd API files) is derived per platform, plus paths for binaries (for Windows only).

Makefile.pdlibbuilder only has 'pdincludepath' for the directory where pd API files should sit, and 'pdbinpath' for the directory where pd.dll should be found on Windows. It doesn't define a root path for pd components, which is particularly inconvenient when you have to type two Windows paths on command line. Why not introduce 'pdpath'?

The thing is, a root path could only work if a standardized directory tree is defined for all pd flavors and build situations. And that is not at all the case. A portable install as used in a centralized build differs from a regular install. Standard pd install locations vary not only per platform (which we can detect), but there's also layout variations per pd flavor. All together it seems impossible to define just one variable and derive appropriate paths from it for all cases. Yet I'd like to make things a bit more convenient. I don't know how yet, this is just brainstorming. Let's start with an overview of standard paths per pd flavor and per platform:

vanilla pd regular installation:

Linux: /usr/include/pd
OSX: /Applications/Pd*.app/Contents/Resources/src
Windows: %PROGRAMFILES%/pd/src
Windows: %PROGRAMFILES%/pd/bin

pd-extended regular installation:

Linux: /usr/include/pdextended
OSX: /Applications/Pd-extended*.app/Contents/Resources/include/pdextended
Windows: %PROGRAMFILES%/pd/include/pdextended
Windows: %PROGRAMFILES%/pd/bin

centralized build:

Linux: $(PD_PATH)/include/pd
OSX: $(PD_PATH)/include/pd
Windows: $(PD_PATH)/include/pd, $(PD_PATH)/bin

Linux:

vanilla pd regular installation: /usr/include/pd
pd-extended regular installation: /usr/include/pdextended
centralized build: $(PD_PATH)/include/pd

OSX:

vanilla pd regular installation: /Applications/Pd*.app/Contents/Resources/src
pd-extended regular installation: /Applications/Pd-extended*.app/Contents/Resources/include/pdextended
centralized build: $(PD_PATH)/include/pd

Windows:

vanilla pd regular installation: %PROGRAMFILES%/pd/src
vanilla pd regular installation: %PROGRAMFILES%/pd/bin
pd-extended regular installation: %PROGRAMFILES%/pd/include/pdextended
pd-extended regular installation: %PROGRAMFILES%/pd/bin
centralized build: $(PD_PATH)/include/pd
centralized build: $(PD_PATH)/bin

Pd-l2ork is another flavor to reckon with. It is the active fork of pd-extended and has inherited the build system. Many makefiles in the pd-l2ork repositories still speak of 'Pd-extended' but it installs under its own application name nowadays. There's no pd-lib-builder in pd-l2ork yet but some day they may want to update actively maintained libs that use it.

Well I don't know what to make of this now. To be continued.

-std=c99 / gnu99

I ran into a snag when using pd-lib-builder to compile an external:

grambidec.c:367:5: error: ‘for’ loop initial declarations are only allowed
in C99 mode
    for(int i = 0; i < 7; i++) {
    ^
grambidec.c:367:5: note: use option -std=c99 or -std=gnu99 to compile your
code

Do we need to include c99 / gnu99 CFLAG in the Makefile?

i386 architecture deprecated for macOS

Mentioned as an aside under #49, the compiler in OSX 10.14 gives this warning when trying to build a fat binary (i386 x86_64). This deserves its own issue because a deprecation warning today may be an error anytime soon.

@megrimm, can you check if the i386 architecture is included in the binary file despite the warning, or is it a native-only build now? You can run command 'file' on the binary to find out.

can we build for macOS 10.6? ("symbol not found ___exp10")

I sent this email to the Pd list and now I wonder if the issue is related to the fact we cannot build for 10.6 with pd-lib-builder, what you say?

here's the screenshot with the error of loading an external built with -pd-lib-builder in macOS 10.6.8
unnamed

Enable setting flags for OS

For my library that I am migrating from the Pd extended library template to the pd-lib-builder Makefile, I need to set OS dependent flags.

Would it be OK to include variables like windows.cflags, linux.ldflags and mac.ldlibs?

Are there any other variables that would make sense to make OS or even architecture dependent? I would implement that and file a pull request for it.

allow multiple architectures of support-library

This is related to #40, but targeted at the "support library" that is built from shared.sources.

problem

Consider a library "foobar", that builds the object classes for [foo] and [bar], that both share some functionality which is collected into a shared library libfoobar.

The makefile looks like:

lib.name = foobar
class.sources = \
   foo.c \
   bar.c \
   $(empty)
shared.sources = \
   foobar.c \
   barfoo.c \
   $(empty)

PDLIBBUILDER_DIR=pd-lib-builder/
include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder

When compiling for Win32 (make) and Win64 (make extension=m_amd64) i get the following files:

# Win32
foobar/foo.dll
foobar/bar.dll
foobar/libfoobar.dll
# Win64
foobar/foo.m_amd64
foobar/bar.m_amd64
foobar/libfoobar.dll

I can almost merge the two directories into a single one that provides binaries for both Win32 and Win64, if it wasn't for the foobar/libfoobar.dll fiile which exists in both directories but is different (as both files have a different architecture).

ld: library not found for -lgcc_s.10.5 (macOS 10.14.3)

getting this error with pd-lib-builder 5.1

ld: library not found for -lgcc_s.10.5
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I do NOT get this error with pd-lib-builder 5.0 meaning everything compiles just fine.
I tried running a diff on the two but fail to see what has changed to cause error. Maybe im missing a new flag I need to add in my Makefile?

C++ externals fail on Windows

just taking @katjav's comment in #39 to a new issue:

All went fine, except one thing: Pd wouldn't load the C++ object in my test set (it works fine on Linux).
I haven't got the opportunity to figure out why but intuition says 'name mangling troubles'.
I don't know how Pd (from Miller's distribution) was built.

Xcode 10 can't build C++ for OSX < 10.9

Reportedly, option -mmacosx-version-min can't be defined lower than 10.9 when building C++ code with Xcode 10. I don't want to set -mmacosx-version-min=10.9 for all Pd libs and regardless of Xcode version. On the other hand I don't know right away how to define it conditionally, which would require two extra checks:

  • is there any C++ code involved in the build?
  • what Xcode version is being used?

Even if these conditions can be checked, the total set of conditional checks for minimum OSX version will become rather kludgy. So I'm hoping that someone comes up with a better idea. In the meantime you may need to override the minimum OSX version as defined in the makefile. This can be done on command line like so:

$ make version.flag="-mmacosx-version-min=10.9"

(edit: version.flag is not considered an 'API' variable, use only as temporary workaround)

If your library needs a specific minimum version anyway, it can be defined in the lib Makefile:

define forDarwin
cflags = -mmacosx-version-min=10.9
endef

how to provide extra dynamic libraries via cmdline?

if i have an external that needs to (dynamically) link against libfoo, i can specify this dependency by adding a line:

ldlibs=-lfoo

However, it seems to be impossible to add libraries during the build process.
I would have expected the build-system to honour the LDLIBS variable, but it seems to be ignored (unlike CPPFLAGS, CFLAGS, CXXFLAGS, LDFLAGS)

$ make LDLIBS=-lfoo
[...]
cc -rdynamic -shared -fPIC -Wl,-rpath,"\$ORIGIN",--enable-new-dtags -o xxx.pd_linux xxx.o  -lc -lm   

(Right now, my main motivation for this is to be able to fix broken 3rd party buildsystems, but there might be more mainstream use-cases as well).

develop source packaging target 'dist', prerequisite for debian / deken packaging

I want to develop target 'dist' as a generalized source packager for distribution targets 'dpkg-source', 'deken-source' / 'deken'. Targets would relate to each other like so:

# make source package
dist: distclean | $(all.sources) $(datafiles) $(datadirs) $(extradist)
    <commands>

# make Debian source package
dpkg-source: dist
    <commands>

# make deken source package
deken-source: dist
    <commands>

# make deken binary package with embedded source package
deken: deken-install
    make deken-source && <other commands>

# make deken binary-only package
deken-no-source: deken-install
    <commands>

# install binaries and data files at custom location for deken packaging
deken-install: installpath := $(tmpdir)/$(lib.name)
deken-install: install

Fred Jan has embedded source tarballs in deken packages 'by hand' and we found it a satisfactory approach. The source tarball doesn't clutter Pd's help browser, and a user can extract it at a location of choice.

With rules chained as indicated above you could still build targets individually, like 'deken-source' for source-only package, or 'deken-install' if you want to test the build before packaging.

Big question though........ how to implement target 'dist'? Conventionally you would replicate the source tree directory layout somewhere and populate it with all the files required for a complete build. For projects with standardized source tree this isn't too difficult because most file names are known to the makefile system anyway. But Makefile.pdlibbuilder doesn't dictate a standard layout. Moreover it doesn't forbid recursive make. Developing a method that can reliably reproduce any source tree may take a long long time.

As a simplistic (temporary?) alternative I've considered packaging the cleaned source tree straight away while exluding specified files and directories. Top level source dir in the package should be renamed $(lib.name)-$(lib.version), which I understand is possible with commands tar and zip.

Is there a good reason to not use the simplistic approach?

specifying a given m_pd.h file

howdy, seems pd-lib-builder will automatically search and find for a pd-extended in your system to build classes, but I'm using new stuff from new vanilla. The way I'm doing it is that i'm replacing files in extended by the new vanilla ones, but there's gotta be a better way that either exists and I dont know about or that we'd have to create.

I was thinking of a way to specify in the makefile which files to use in a subfolder or something, then I could have it in some of my projects subfolder.

cheers

Enable cross compilation

There needs to be a way to override the architecture detection to enable cross compilation, e.g. for compilation with MXE or armhf from amd64.

class.sources that are added in a `forLinux` clause are not built

i just stumbled upon this while modernizing hcs.

if i have an objectclass that should only build for a given platform, the documentation says to wrap it into a define forXXX clause:

# forLinux, forDarwin, forWindows:
# Shorthand for 'variable definitions for Linux only' etc. Use like:
# define forLinux
# cflags += -DLINUX
# class.sources += linuxthing.c
# endef

However, doing so does not actually work: the specified classes are not build at all.
However, the define does work, as can be seen from other variables used in the clause.

consider the following replacement of the helloworld Makefile:

# Makefile to build class 'helloworld' for Pure Data.
# Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build
# settings and rules.

# library name
lib.name = helloworld

# input source file (class name == source file basename)
class.sources =
datafiles = helloworld-meta.pd README.md

define forLinux
  class.sources += test.c
  datafiles += helloworld-help.pd
endef

# include Makefile.pdlibbuilder from submodule directory 'pd-lib-builder'
PDLIBBUILDER_DIR=pd-lib-builder/
include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder

Running make does not do anything.
Running make install will install the following files:

$ ls -1 .../helloworld/
helloworld-help.pd
helloworld-meta.pd
README.md

so the "helloworld.pd_linux" is missing, but the "helloworld-help.pd" gets installed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.