#!/bin/sh
#
# Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
#
# All rights reserved.
#
# This file is part of ObjFW. It may be distributed under the terms of the
# Q Public License 1.0, which can be found in the file LICENSE.QPL included in
# the packaging of this file.
#
# Alternatively, it may be distributed under the terms of the GNU General
# Public License, either version 2 or 3, which can be found in the file
# LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
# file.
#
if test x"$(basename "$0")" != x"objfw-compile"; then
OBJFW_CONFIG="$(basename "$0" | sed 's/-objfw-compile$//')-objfw-config"
else
OBJFW_CONFIG="objfw-config"
fi
if ! which $OBJFW_CONFIG >/dev/null 2>&1; then
echo "You need to have ObjFW and $OBJFW_CONFIG installed!"
exit 1
fi
parse_packages() {
packages=""
while test x"$1" != "x"; do
case "$1" in
--package)
shift
packages="$packages --package $1"
;;
esac
shift
done
}
parse_packages "$@"
show_help() {
cat >&2 <<__EOF__
Syntax: objfw-compile -o output [flags] source1.m source2.mm ...
-o name Specify the output name (not file name!)
--arc Use automatic reference counting
--lib version Compile a library (with the specified version) instead of
an application
--plugin Compile a plugin instead of an application
--package name Use the specified package
--builddir dir Place built objects into the specified directory
-D* -D * Pass the specified define to the compiler
-framework * Pass the specified -framework argument to the linker
(macOS / iOS only)
-f* Pass the specified -f flag to the compiler
-F* -F * Pass the specified -F flag to the linker (macOS / iOS only)
-g* Pass the specified -g flag to the compiler
-I* -I * Pass the specified -I flag to the compiler
-l* -l * Pass the specified -l flag to the linker
-L* -L * Pass the specified -L flag to the linker
-m* Pass the specified -m flag to the compiler
-O* Pass the specified -O flag to the compiler
-pthread Pass -pthread to the compiler and linker
-std=* Pass the specified -std= flag to the compiler
-Wl,* Pass the specified -Wl, flag to the linker
-W* Pass the specified -W flag to the compiler
--help Show this help
__EOF__
}
CPPFLAGS="$CPPFLAGS $($OBJFW_CONFIG $packages --cppflags)"
OBJC="$($OBJFW_CONFIG --objc)"
OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG $packages --objcflags) -Wall -g"
LIBS="$LIBS $($OBJFW_CONFIG $packages --libs)"
LDFLAGS="$LDFLAGS $($OBJFW_CONFIG $packages --ldflags --rpath)"
if test x"$1" = "x"; then
show_help
exit 1
fi
status_compiling() {
printf "\033[K\033[0;33mCompiling \033[1;33m%s\033[0;33m...\033[0m\r" \
"$1"
}
status_compiled() {
printf "\033[K\033[0;32mSuccessfully compiled \033[1;32m%s\033[0;32m." \
"$1"
printf "\033[0m\n"
}
status_compile_failed() {
printf "\033[K\033[0;31mFailed to compile \033[1;31m%s\033[0;31m!" "$1"
printf "\033[0m\n"
exit $2
}
status_linking() {
printf "\033[K\033[0;33mLinking \033[1;33m%s\033[0;33m...\033[0m\r" "$1"
}
status_linked() {
printf "\033[K\033[0;32mSuccessfully linked \033[1;32m%s\033[0;32m." \
"$1"
printf "\033[0m\n"
}
status_link_failed() {
printf "\033[K\033[0;31mFailed to link \033[1;31m%s\033[0;31m!" "$1"
printf "\033[0m\n"
exit $2
}
srcs=""
out=""
objs=""
builddir=""
link="no"
link_stdcpp="no"
lib="no"
plugin="no"
out_prefix=""
out_suffix=""
while test x"$1" != "x"; do
case "$1" in
-o|--out)
shift
out="$1"
;;
--lib)
if test x"$plugin" = x"yes"; then
echo "You can't use --lib and --plugin!"
exit 1
fi
shift
if ! echo "$1" | grep "^[0-9]\+\.[0-9]\+$" >/dev/null; then
echo "$1 is not a valid library version!"
exit 1
fi
export LIB_MAJOR="${1%.*}"
export LIB_MINOR="${1#*.}"
lib="yes"
OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --lib-cflags)"
out_prefix="$($OBJFW_CONFIG --lib-prefix)"
out_suffix="$($OBJFW_CONFIG --lib-suffix)"
;;
--package)
# Already included into the flags.
shift
;;
--plugin)
if test x"$lib" = x"yes"; then
echo "You can't use --lib and --plugin!"
exit 1
fi
plugin="yes"
OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --plugin-cflags)"
LDFLAGS="$LDFLAGS $($OBJFW_CONFIG --plugin-ldflags)"
out_suffix="$($OBJFW_CONFIG --plugin-suffix)"
;;
--arc)
OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --arc)"
;;
--builddir)
shift
builddir="$1"
;;
-D)
shift
CPPFLAGS="$CPPFLAGS -D$1"
;;
-D*)
CPPFLAGS="$CPPFLAGS $1"
;;
-framework)
shift
LIBS="$LIBS -framework $1"
;;
-f*)
OBJCFLAGS="$OBJCFLAGS $1"
;;
-F)
shift
LIBS="$LIBS -F$1"
;;
-F*)
LIBS="$LIBS $1"
;;
-g*)
OBJCFLAGS="$OBJCFLAGS $1"
;;
-I)
shift
CPPFLAGS="$CPPFLAGS -I$1"
;;
-I*)
CPPFLAGS="$CPPFLAGS $1"
;;
-l)
shift
LIBS="$LIBS -l$1"
;;
-l*)
LIBS="$LIBS $1"
;;
-L)
shift
LIBS="$LIBS -L$1"
;;
-L*)
LIBS="$LIBS $1"
;;
-m*)
OBJCFLAGS="$OBJCFLAGS $1"
;;
-O*)
OBJCFLAGS="$OBJCFLAGS $1"
;;
-pthread)
OBJCFLAGS="$OBJCFLAGS $1"
LDFLAGS="$LDFLAGS $1"
;;
-std=*)
OBJCFLAGS="$OBJCFLAGS $1"
;;
-Wl,*)
LDFLAGS="$LDFLAGS $1"
;;
-W*)
OBJCFLAGS="$OBJCFLAGS $1"
;;
--help)
show_help
exit 0
;;
-*)
echo "Unknown option: $1"
exit 1
;;
*.m)
srcs="$srcs $1"
;;
*.mm)
srcs="$srcs $1"
link_stdcpp="yes"
;;
*)
echo "Only .m and .mm files can be compiled!" 1>&2
exit 1
;;
esac
shift
done
if test x"$out" = x""; then
echo "No output name specified! Use -o or --out!"
exit 1
fi
case "$builddir" in
"")
;;
*/)
;;
*)
builddir="$builddir/"
;;
esac
for i in $srcs; do
case $i in
*.m)
if test x"$lib" = x"yes"; then
obj="$builddir${i%.m}.lib.o"
elif test x"$plugin" = x"yes"; then
obj="$builddir${i%.m}.plugin.o"
else
obj="$builddir${i%.m}.o"
fi
;;
*.mm)
if test x"$lib" = x"yes"; then
obj="$builddir${i%.mm}.lib.o"
elif test x"$plugin" = x"yes"; then
obj="$builddir${i%.mm}.plugin.o"
else
obj="$builddir${i%.mm}.o"
fi
;;
esac
objs="$objs $obj"
build="no"
deps=$($OBJC -E -M $CPPFLAGS $OBJCFLAGS $i |
sed 's/.*: //' | sed 's/\\//g')
if test -f "$obj"; then
for dep in $deps; do
test "$dep" -nt $obj && build="yes"
done
else
build="yes"
fi
if test x"$build" = x"yes"; then
link="yes"
status_compiling $i
mkdir -p "$(dirname $obj)" || status_compile_failed $i $?
$OBJC $CPPFLAGS $OBJCFLAGS -c -o $obj $i || \
status_compile_failed $i $?
status_compiled $i
fi
done
test x"$lib" = x"no" -a x"$plugin" = x"no" && \
out_suffix="$($OBJFW_CONFIG --prog-suffix)"
test x"$link_stdcpp" = x"yes" && LIBS="$LIBS -lstdc++"
if test x"$lib" = x"yes"; then
export SHARED_LIB="$out_prefix$out$out_suffix"
LDFLAGS="$LDFLAGS $($OBJFW_CONFIG --lib-ldflags)"
fi
if test x"$plugin" = x"yes" -a x"$out_suffix" = x".bundle"; then
# If $out_suffix is .bundle, it means we are creating a macOS bundle.
# These are not just a single file, but have a certain directory
# structure. Therefore we amend the output path to match the expected
# directory structure.
mkdir -p $out$out_suffix/Contents/MacOS
out="$out$out_suffix/Contents/MacOS/$(basename $out)"
out_suffix=""
fi
if test ! -f "$out_prefix$out$out_suffix" -o x"$link" = x"yes"; then
status_linking $out_prefix$out$out_suffix
$OBJC -o $out_prefix$out$out_suffix $objs $LIBS $LDFLAGS || \
status_link_failed $out $?
status_linked $out_prefix$out$out_suffix
fi