Using Autotools for a project with platform specific source code
Asked Answered
C

3

7

I'm developing a project that is currently written in C but I plan to write some of the functions in ASM for at least two platforms (x86_64 and arm). So I might have some source files:

  • generic/one.c
  • generic/two.c
  • generic/three.c
  • arm/one.s
  • x86_64/two.s

I'd like it so that the configure script chooses the .s files over the .c files when possible. So building on arm will be one.s, two.c, three.c etc.

It seems difficult or impossible to do this nicely with Automake. But if I ditch Automake I'll have to track my own dependencies (ugh).

What's the best way to do this?

Conformist answered 13/3, 2013 at 23:42 Comment(1)
"But if I ditch automake I'll have to track my own dependencies (ugh)." that's a false dichotomy! Don't forget about tools such as CMake. In fact, here's a big listTaunton
S
2

The Conditional Sources section of the automake manual should point you in the right direction. You're going to want AC_CANONICAL_HOST in configure.ac and then make decisions based on the value of $host.

automake won't like it if two files can compile to the same object. If you can't rename the sources like in the linked part of the manual, you may want to try something like this (make sure you have subdir-objects in AM_INIT_AUTOMAKE:

# Note the $() isn't a shell command substitution.
# The quoting means it'll be expanded by `make'.
MODULE_ONE_OBJ='generic/one.$(OBJEXT)'
MODULE_TWO_OBJ='generic/two.$(OBJEXT)'
case $host in
  # ...
  arm*)
    MODULE_ONE='arm/one.$(OBJEXT)'
    ;;
  x86_64)
    MODULE_TWO='x86/two.$(OBJEXT)'
    ;;
esac
AC_SUBST([MODULE_ONE])
AC_SUBST([MODULE_TWO])

In Makefile.am:

bin_PROGRAMS = foo
foo_SOURCES = foo.c
EXTRA_foo_SOURCES = arm/one.s x86/two.c
foo_LDADD = $(MODULE_ONE) $(MODULE_TWO)
foo_DEPENDENCIES = $(MODULE_ONE) $(MODULE_TWO)
Stpeter answered 14/3, 2013 at 1:13 Comment(1)
I had already figured out how to do that bit in configure.ac, the trouble is that even if you add one.c and one.s to build_SOURCES conditionally in Makefile.am, automake will complain that they both generate one.o.Conformist
C
4

Here's what I do.

configure.ac

...
AC_CANONICAL_SYSTEM
AM_PROG_AS
AC_PROG_CC
...
PROC=""
AS_CASE([$host_cpu], [x86_64], [PROC="x86_64"], [arm*], [PROC="arm"])

AM_CONDITIONAL([CPU_X86_64], [test "$PROC" = "x86_64"])
AM_CONDITIONAL([CPU_ARM], [test "$PROC" = "arm"])
AM_CONDITIONAL([CPU_UNDEFINED], [test "x$PROC" = "x"])

Makefile.am

lib_LTLIBRARIES = libfoo.la
libfoo_la_SOURCES = \
$(top_srcdir)/generic/three.c

if CPU_ARM
libfoo_la_SOURCES += $(top_srcdir)/arm/one.s \
$(top_srcdir)/generic/two.c
endif

if CPU_X86_64
libfoo_la_SOURCES += $(top_srcdir)/generic/one.c \
$(top_srcdir)/x86_64/two.s
endif

if CPU_UNDEFINED
libfoo_la_SOURCES += $(top_srcdir)/generic/one.c \
$(top_srcdir)/generic/two.c
endif
Chorography answered 14/3, 2013 at 17:55 Comment(0)
S
2

The Conditional Sources section of the automake manual should point you in the right direction. You're going to want AC_CANONICAL_HOST in configure.ac and then make decisions based on the value of $host.

automake won't like it if two files can compile to the same object. If you can't rename the sources like in the linked part of the manual, you may want to try something like this (make sure you have subdir-objects in AM_INIT_AUTOMAKE:

# Note the $() isn't a shell command substitution.
# The quoting means it'll be expanded by `make'.
MODULE_ONE_OBJ='generic/one.$(OBJEXT)'
MODULE_TWO_OBJ='generic/two.$(OBJEXT)'
case $host in
  # ...
  arm*)
    MODULE_ONE='arm/one.$(OBJEXT)'
    ;;
  x86_64)
    MODULE_TWO='x86/two.$(OBJEXT)'
    ;;
esac
AC_SUBST([MODULE_ONE])
AC_SUBST([MODULE_TWO])

In Makefile.am:

bin_PROGRAMS = foo
foo_SOURCES = foo.c
EXTRA_foo_SOURCES = arm/one.s x86/two.c
foo_LDADD = $(MODULE_ONE) $(MODULE_TWO)
foo_DEPENDENCIES = $(MODULE_ONE) $(MODULE_TWO)
Stpeter answered 14/3, 2013 at 1:13 Comment(1)
I had already figured out how to do that bit in configure.ac, the trouble is that even if you add one.c and one.s to build_SOURCES conditionally in Makefile.am, automake will complain that they both generate one.o.Conformist
C
2

You can use AC_CANONICAL_HOST and then conditionally select the correct subdirectory. For example, in configure.ac:

AC_CANONICAL_HOST
AC_SUBST([USE_DIR],[$host_cpu])
test -d $srcdir/$USE_DIR || USE_DIR=generic

and then in Makefile.am:

SUBDIRS = $(USE_DIR) common

and in common/Makefile.am:

LDADD = ../$(USE_DIR)/libfoo.a

and in each ${host_cpu}/Makefile.am:

noinst_LIBRARIES = libfoo.a
libfoo_a_SOURCES = one.s ../common/two.c

This uses a slightly different directory structure than you describe. C files that are used on all platforms would go in common and be linked to a convenience library constructed in the platform specific directory. If some c files are used on only some platforms, you could put them in common and reference them explicitly in the Makefile.am for the platforms that need them.

Calabar answered 14/3, 2013 at 8:49 Comment(4)
Is that going to break make dist?Stpeter
It should be $host_cpu not $target_cpu but something like this could work. Target is for things like compilers that can be configured to be built to compile for other platforms (cross-compiler). I did already think of something similar but ran into trouble again.Conformist
Also: AC_CANONICAL_TARGET is not what you want. --target is for setting the target architecture of compilers. --host is the machine that runs the built binaries.Stpeter
make dist should be ok since i686/Makefile.am will be listed in AC_CONFIG_FILES, but it probably doesn't hurt to explicitly list the platform specific directories in DIST_SUBDIRSCalabar

© 2022 - 2024 — McMap. All rights reserved.