haiku/Jamrules
Matthew Wilber c407191357 Added rule for building screen savers
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10391 a95241bf-73f2-0310-859d-f6bbb57e9c96
2004-12-11 21:58:09 +00:00

2308 lines
59 KiB
Plaintext

# Vanilla Jam compatibility
if ! $(INVOCATION_SUBDIR_SET) {
rule FIsPrefix
{
# FIsPrefix <a> : <b> ;
# Returns true, if list <a> is a prefix (a proper one or equal) of
# list <b>, an empty list otherwise.
local a = $(1) ;
local b = $(2) ;
while $(a) && $(a[1]) = $(b[1]) {
a = $(a[2-]) ;
b = $(b[2-]) ;
}
if $(a) {
return ;
} else {
return true ;
}
}
rule LocalClean { Clean $(1) : $(2) ; }
rule LocalDepends { Depends $(1) : $(2) ; }
} # vanilla Jam compatibility
# The directory for build system specific files
OBOS_BUILD_DIR = [ FDirName $(OBOS_TOP) build ] ;
# Cache files for header scanning and jamfile caching
HCACHEFILE = header_cache ;
JCACHEFILE = jamfile_cache ;
LOCATE on $(HCACHEFILE) $(JCACHEFILE) = $(OBOS_BUILD_DIR) ;
# Include BuildConfig
{
local buildConfig = [ GLOB $(OBOS_BUILD_DIR) : BuildConfig ] ;
if ! $(buildConfig)
{
ECHO "No BuildConfig found in $(OBOS_BUILD_DIR)!" ;
EXIT "Run ./configure in the source tree's root directory first!" ;
}
LOCATE on BuildConfig = $(OBOS_BUILD_DIR) ;
include BuildConfig ;
}
# analyze GCC version
if ! $(GCC_RAW_VERSION) {
ECHO "Variable GCC_RAW_VERSION not set. Please run ./configure or" ;
EXIT "specify it manually." ;
}
GCC_VERSION = ;
{
# split the raw version string at `.' and `-' characters
local version = $(GCC_RAW_VERSION) ;
while $(version) {
local split = [ Match "([^.-]*)[.-](.*)" : $(version) ] ;
if $(split) {
GCC_VERSION += $(split[1]) ;
version = $(split[2]) ;
} else {
GCC_VERSION += $(version) ;
version = ;
}
}
}
# Save the platform default headers.
PLATFORM_DEFAULT_HEADERS = $(HDRS) ;
# Add some grist to the libgcc objects
LIBGCC_OBJECTS = $(LIBGCC_OBJECTS:G=libgcc) ;
# We do not include any local BeOS system headers by default
CCFLAGS += -nostdinc ;
C++FLAGS += -nostdinc ;
# Allow compiling unit tests on Zeta. Instead of fixing the PostMessage()
# issues, they deprecated that nice function. This will enable it again:
C++FLAGS += -D_ZETA_USING_DEPRECATED_API_=1 ;
if ! $(TARGET_PLATFORM) {
ECHO "Variable TARGET_PLATFORM not set. Please run ./configure or" ;
EXIT "specify it manually." ;
}
switch $(TARGET_PLATFORM)
{
case r5 :
{
# "everything" is r5 compatible
}
case bone :
{
BONE_COMPATIBLE = true ;
}
case dano :
{
BONE_COMPATIBLE = true ;
DANO_COMPATIBLE = true ;
}
case haiku :
{
BONE_COMPATIBLE = true ;
DANO_COMPATIBLE = true ;
HAIKU_COMPATIBLE = true ;
DEFINES += __HAIKU__ ;
}
}
if $(BONE_COMPATIBLE) {
NETWORK_LIBS = libsocket.so libbind.so ;
SELECT_UNAME_ETC_LIB = libroot.so ;
} else {
NETWORK_LIBS = libnet.so ;
SELECT_UNAME_ETC_LIB = libnet.so ;
}
# Determine if we're building on PPC or x86
# Determine mimetype of executable
# Cross compiling can come later
TARGET_CPU ?= $(OSPLAT:L) ;
OBOS_VERSION ?= R1 ;
switch $(TARGET_CPU) {
case ppc :
{
if $(METROWERKS) {
# at least parts of OpenBeOS still can be compiled with
# the Metrowerks compiler on BeOS/PPC
OBOS_TARGET_TYPE ?= "application/x-be-executable" ;
} else {
OBOS_TARGET_TYPE ?= "application/x-vnd.Be-elfexecutable" ;
}
DEFINES += __POWERPC__ ARCH_ppc ;
OBOS_BOOT_PLATFORM = openfirmware ;
}
case x86 :
{
# nothing special to do here...
DEFINES += __INTEL__ ARCH_x86 ;
OBOS_BOOT_PLATFORM = bios_ia32 ;
}
case * :
Exit "Currently unsupported build platform:" $(TARGET_CPU) ;
}
# set target specific variables
{
#Echo "Building for" $(TARGET_CPU) ;
OBOS_TARGET ?= $(TARGET_CPU).$(OBOS_VERSION) ;
OBOS_TARGET_TYPE ?= "application/x-vnd.Be-elfexecutable" ;
OBOS_ARCH ?= $(TARGET_CPU) ;
OBOS_TARGET_DEFINE ?= "ARCH_"$(TARGET_CPU) ;
}
# Disable warnings only if WARNINGS is set to 0
# Should be enabled by default later
#
WARNINGS ?= 1 ;
if $(WARNINGS) = 1 {
# For an explanation of the different warning options, see:
# http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_2.html
# to get even more warnings, add:
# -Wwrite-strings (doesn't work well with some Be headers)
# -Wundef (dito)
# -Wconversion (gets you many warnings about implicit conversions)
# -W (gets you even more warnigs)
CCFLAGS += -Wall -Wno-multichar -Wmissing-prototypes ;
CCFLAGS += -Wpointer-arith -Wcast-align -Wsign-compare ;
C++FLAGS += -Wall -Wno-multichar -Wmissing-prototypes -Wno-ctor-dtor-privacy -Woverloaded-virtual ;
C++FLAGS += -Wpointer-arith -Wcast-align -Wsign-compare ;
} else {
CCFLAGS += -Wno-multichar ;
C++FLAGS += -Wno-multichar ;
}
# standard kernel C/C++ flags
KERNEL_CCFLAGS ?= -Wall -Wno-multichar -Wmissing-prototypes -finline -nostdinc ;
KERNEL_CCFLAGS += -fno-builtin -D$(OBOS_TARGET_DEFINE) ;
KERNEL_CCFLAGS += -DBOCHS_DEBUG_HACK=$(BOCHS_DEBUG_HACK) -D_KERNEL_MODE ;
KERNEL_C++FLAGS ?= -Wall -Wno-multichar -Wmissing-prototypes -finline -nostdinc ;
KERNEL_C++FLAGS += -fno-builtin -fno-exceptions -D$(OBOS_TARGET_DEFINE) ;
KERNEL_C++FLAGS += -DBOCHS_DEBUG_HACK=$(BOCHS_DEBUG_HACK) -D_KERNEL_MODE ;
if $(GCC_VERSION[1]) >= 3 {
KERNEL_C++FLAGS += -fno-use-cxa-atexit ;
}
# We might later want to introduce debug levels or handle the whole issue
# differently. For now there's only on or off.
#
DEBUG ?= 0 ;
if $(DEBUG) != 0 {
OPTIM ?= -O0 ;
CCFLAGS += -g [ FDefines DEBUG=$(DEBUG) ] ;
C++FLAGS += -g [ FDefines DEBUG=$(DEBUG) ] ;
KERNEL_CCFLAGS += -g [ FDefines DEBUG=$(DEBUG) ] ;
KERNEL_C++FLAGS += -g [ FDefines DEBUG=$(DEBUG) ] ;
LINKFLAGS += -g ;
} else {
OPTIM ?= -O2 ;
}
#
# To disable for the tests OPTIM and DEBUG are overridden, set the environment
# variable NO_TEST_DEBUG.
# Instructs the Library rule to not make its object files temporary.
# This is needed as some objects are used in a static library and for an
# executable.
KEEPOBJS = true ;
# under BeOS use copyattr instead of cp
if $(OS) = BEOS
{
CP = copyattr --data ;
}
# for builds of tools in the current environment
if $(OS) = BEOS {
BUILD_LIBSTDC++ = stdc++.r4 ;
} else {
BUILD_LIBSTDC++ = stdc++ ;
}
# If no OBOS_OBJECT_TARGET is not defined yet, use our default directory and
# include our "OBOS_TARGET" as subdirectory in there (to prevent different
# builds mixing objects from different targets).
if ! $(OBOS_OBJECT_TARGET) {
OBOS_OBJECT_TARGET ?= [ FDirName $(OBOS_TOP) objects $(OBOS_TARGET) ] ;
}
# If no OBOS_DISTRO_TARGET is not defined yet, use our default directory and
# include our "OBOS_TARGET" as subdirectory in there (to prevent different
# builds mixing executables from different targets).
if ! $(OBOS_DISTRO_TARGET) {
OBOS_DISTRO_TARGET ?= [ FDirName $(OBOS_TOP) distro $(OBOS_TARGET) ] ;
}
# Set our version number if not already set and mark it as a developer build
if ! $(OBOS_BUILD_VERSION) {
OBOS_BUILD_VERSION ?= "1 0 0 a 1" ;
OBOS_BUILD_DESCRIPTION ?= "Developer Build" ;
}
# If OBOS_BUILD_VERSION is set, but OBOS_BUILD_DESCRIPTION isn't, mark it as
# an unknown build.
if ! $(OBOS_BUILD_DESCRIPTION) {
OBOS_BUILD_DESCRIPTION ?= "Unknown Build" ;
}
# Relative subdirs for distro dir
OBOS_ADDON_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos system add-ons ] ;
OBOS_APPS_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos apps ] ;
OBOS_BIN_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos bin ] ;
OBOS_ETC_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos etc ] ;
OBOS_FONTS_DIR ?= [ FDirName $(OBOS_ETC_DIR) fonts ] ;
OBOS_KERNEL_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos system ] ;
OBOS_PREFS_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos preferences ] ;
OBOS_SERVER_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos system servers ] ;
OBOS_SHLIB_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos system lib ] ;
OBOS_STLIB_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) develop lib
$(OBOS_ARCH) ] ;
OBOS_TEST_DIR ?= [ FDirName $(OBOS_TOP) tests ] ;
OBOS_PACKAGE_DIR ?= [ FDirName $(OBOS_TOP) packages $(OBOS_TARGET) ] ;
OBOS_PACKAGE_OBJECT_DIR ?= [ FDirName $(OBOS_OBJECT_TARGET) packages ] ;
OBOS_KERNEL_CONFIG = config.$(OBOS_ARCH).ini ;
OBOS_KERNEL = kernel.$(OBOS_ARCH) ;
OBOS_FLOPPY = floppy.$(OBOS_ARCH) ;
rule SetupIncludes
{
# XXX add "opengl" later
local os_includes = add-ons add-ons/file_system add-ons/graphics add-ons/input_server add-ons/screen_saver add-ons/tracker app device drivers game interface kernel media mail midi midi2 net storage support translation ;
# Overwrite any exiting content when changing HDRS. This rule may be invoked multiple times.
# Use headers directory, to allow to do things like include <posix/string.h>
HDRS = [ FDirName $(OBOS_TOP) headers ] ;
# Use posix headers directory
HDRS += [ FDirName $(OBOS_TOP) headers posix ] ;
# Use public OS header directories
HDRS += [ PublicHeaders $(os_includes) ] ;
# Use the root of the private headers -- not so nice, but simplifies things.
HDRS += [ PrivateHeaders $(DOT) ] ;
# Used as a fallback, the R5 header directories (we should remove this as soon as possible)
HDRS += /boot/develop/headers/posix /boot/develop/headers/cpp ;
# The platform dependent headers.
HDRS += $(PLATFORM_HEADERS) ;
}
rule SetupR5Includes
{
# Unsets HDRS, so that the OBOS headers do not `shadow' the system headers.
HDRS = ;
}
rule SetupDefaultIncludes
{
# Resets HDRS to the default headers for the build platform.
HDRS = $(PLATFORM_DEFAULT_HEADERS) ;
}
#-------------------------------------------------------------------------------
# Things Jam needs in order to work :)
#-------------------------------------------------------------------------------
# TODO: back-ported from jam 2.5: remove when not longer needed
rule MakeLocate
{
if $(>)
{
LOCATE on $(<) = $(>) ;
Depends $(<) : $(>[1]:G=dir) ;
MkDir $(>[1]:G=dir) ;
}
}
rule Object
{
# This is basically the original Jambase 2.4 Object rule stripped by
# comments. Only the final switch statement has been changed to allow
# intermediate C++ files for Yacc and Lex.
LocalClean clean : $(<) ;
MakeLocate $(<) : $(LOCATE_TARGET) ;
SEARCH on $(>) = $(SEARCH_SOURCE) ;
HDRS on $(<) = $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ;
HDRRULE on $(>) = HdrRule ;
HDRSCAN on $(>) = $(HDRPATTERN) ;
HDRSEARCH on $(>) =
$(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(HDRS) $(STDHDRS) ;
HDRGRIST on $(>) = $(HDRGRIST) ;
DEFINES on $(<) += $(DEFINES) ;
# if source is not .c, generate .c with specific rule
switch $(>:S)
{
case .asm : As $(<) : $(>) ;
case .c : Cc $(<) : $(>) ;
case .C : C++ $(<) : $(>) ;
case .cc : C++ $(<) : $(>) ;
case .cpp : C++ $(<) : $(>) ;
case .f : Fortran $(<) : $(>) ;
case .l : if [ on $(2) return $(GENERATE_C++) ] {
C++ $(<) : $(<:S=.cpp) ;
LexC++ $(<:S=.cpp) : $(>) ;
} else {
Cc $(<) : $(<:S=.c) ;
Lex $(<:S=.c) : $(>) ;
}
case .s : As $(<) : $(>) ;
case .y : if [ on $(2) return $(GENERATE_C++) ] {
C++ $(<) : $(<:S=.cpp) ;
Bison $(<:S=.cpp) : $(>) ;
} else {
Cc $(<) : $(<:S=$(YACCGEN)) ;
Yacc $(<:S=$(YACCGEN)) : $(>) ;
}
case * : UserObject $(<) : $(>) ;
}
}
rule UserObject
{
switch $(2)
{
case *.S : assemble $(1) : $(2) ;
case *.o : return ;
case * : ECHO "unknown suffix on" $(2) ;
}
}
# Override the default to give "prettier" command lines.
actions Cc
{
$(CC) -c "$(2)" $(CCFLAGS) $(CCDEFS) $(CCHDRS) -o "$(1)" ;
}
actions C++
{
$(C++) -c "$(2)" $(C++FLAGS) $(CCDEFS) $(CCHDRS) -o "$(1)" ;
}
#-------------------------------------------------------------------------------
# General High-level OBOS target rules
#-------------------------------------------------------------------------------
rule App
{
# App <name> : <sources> : <libraries> : <res> ;
SetupIncludes ;
SetupObjectsDir ;
AddResources $(1) : $(4) ;
Main $(1) : $(2) ;
MakeLocate $(1) : $(OBOS_APPS_DIR) ;
LinkSharedOSLibs $(1) : $(3) ;
LINKFLAGS on $(1) = [ on $(1) return $(LINKFLAGS) ]
-Xlinker -soname=_APP_ ;
}
rule BinCommand
{
# BinCommand <name> : <sources> : <libraries> : <res> ;
SetupIncludes ;
SetupObjectsDir ;
AddResources $(1) : $(4) ;
Main $(1) : $(2) ;
MakeLocate $(1) : $(OBOS_BIN_DIR) ;
LinkSharedOSLibs $(1) : $(3) ;
LINKFLAGS on $(1) = [ on $(1) return $(LINKFLAGS) ]
-Xlinker -soname=_APP_ ;
}
rule StdBinCommands
{
# StdBinCommands <sources> : <libs> : <res> ;
SetupIncludes ;
SetupObjectsDir ;
local libs = $(2) ;
local ress = $(3) ;
local source ;
for source in $(1)
{
local target = $(source:S=) ;
BinCommand $(target) : $(source) : $(libs) : $(ress) ;
}
}
rule Preference
{
# Preference <name> : <sources> : <libraries> ;
SetupIncludes ;
SetupObjectsDir ;
Main $(1) : $(2) ;
MakeLocate $(1) : $(OBOS_PREFS_DIR) ;
LinkSharedOSLibs $(1) : $(3) ;
LINKFLAGS on $(1) = [ on $(1) return $(LINKFLAGS) ]
-Xlinker -soname=_APP_ ;
}
rule Server
{
# Server <name> : <sources> : <libraries> ;
SetupIncludes ;
SetupObjectsDir ;
Main $(1) : $(2) ;
MakeLocate $(1) : $(OBOS_SERVER_DIR) ;
LinkSharedOSLibs $(1) : $(3) ;
LINKFLAGS on $(1) = [ on $(1) return $(LINKFLAGS) ]
-Xlinker -soname=_APP_ ;
}
# test pseudo targets
NOTFILE obostests ;
NOTFILE r5tests ;
rule CommonTestLib
{
# CommonTestLib <target> : <sources> : <obos libraries>
# : <r5 libraries> : <test libraries> : <public headers>;
# Builds a unit test for both OBOS and R5 modules.
# <target> The name of the target.
# <sources> The list of sources.
# <obos libraries> A list of link libraries for the OBOS tests (as passed
# to LinkSharedOSLibs).
# <r5 libraries> A list of link libraries for the R5 tests (as passed
# to LinkSharedOSLibs).
# <test libraries> A list of link libraries for both OBOS tests and R5 tests
# that have a common name (i.e. specify libx.so and the OBOS tests will link
# to libx.so and the R5 tests will link to libx_r5.so).
# <public headers> A list of public header dirs (as passed to
# UsePublicHeaders).
TestLib $(1) : $(2) : [ FDirName $(OBOS_TEST_DIR) unittester lib ] : $(3) $(5) : $(6) ;
R5TestLib $(1) : $(2) : [ FDirName $(OBOS_TEST_DIR) unittester_r5 lib ] : $(4) [ R5SharedLibraryNames $(5) ] ;
}
rule TestLib
{
# TestLib <target> : <sources> : <dest> : <libraries> : <public headers>
# Builds a unit test library for an OBOS module.
# <target> The name of the target.
# <sources> The list of sources.
# <dest> The directory for the target (as passed to FDirName).
# <libraries> A list of link libraries (as passed to LinkSharedOSLibs).
# <public headers> A list of public header dirs (as passed to
# UsePublicHeaders).
local target = $(1) ;
local sources = $(2) ;
local dest = $(3) ;
local libraries = $(4) ;
local headerDirs = $(5) ;
local objects = [ FGristFiles $(sources:S=$(SUFOBJ)) ] ;
# Our Main replacement.
MainFromObjects $(target) : $(objects) ;
TestObjects $(sources) : $(headerDirs) ;
MakeLocate $(target) : $(dest) ;
Depends $(target) : libcppunit.so ;
Depends obostests : $(target) ;
LinkSharedOSLibs $(target) : libcppunit.so $(libraries) ;
LINKFLAGS on $(target) = $(LINKFLAGS) -nostart -Xlinker -soname=\"$(target)\" ;
}
rule R5TestLib
{
# R5TestLib <target> : <sources> : <dest> : <libraries>
# Builds a unit test for an R5 module. "_r5" is appended to the object
# and the target name.
# <target> The name of the target.
# <sources> The list of sources.
# <dest> The directory for the target (as passed to FDirName).
# <libraries> A list of link libraries (as passed to LinkSharedOSLibs).
local target = $(1:B)_r5$(1:S) ;
local sources = $(2) ;
local dest = $(3) ;
local libraries = $(4) ;
local objects = [ R5ObjectNames $(sources) ] ;
# Our Main replacement.
MainFromObjects $(target) : $(objects) ;
TestObjects $(sources) : : true ;
MakeLocate $(target) : $(dest) ;
Depends $(target) : libcppunit.so ;
Depends r5tests : $(target) ;
LinkSharedOSLibs $(target) : libcppunit.so $(libraries) ;
LINKFLAGS on $(target) = $(LINKFLAGS) -nostart -Xlinker -soname=\"$(target)\" ;
}
rule CommonUnitTest
{
# CommonUnitTest <target> : <sources> : <dest> : <obos libraries>
# : <r5 libraries> : <public headers>;
# Builds a unit test for both OBOS and R5 modules.
# <target> The name of the target.
# <sources> The list of sources.
# <dest> The directory for the target (as passed to FDirName).
# <obos libraries> A list of link libraries for the OBOS tests (as passed
# to LinkSharedOSLibs).
# <r5 libraries> A list of link libraries for the R5 tests (as passed
# to LinkSharedOSLibs).
# <public headers> A list of public header dirs (as passed to
# UsePublicHeaders).
UnitTest $(1) : $(2) : $(3) : $(4) : $(6) ;
R5UnitTest $(1) : $(2) : $(3) : $(5) ;
}
rule UnitTest
{
# UnitTest <target> : <sources> : <dest> : <libraries> : <public headers>
# Builds a unit test for an OBOS module.
# <target> The name of the target.
# <sources> The list of sources.
# <dest> The directory for the target (as passed to FDirName).
# <libraries> A list of link libraries (as passed to LinkSharedOSLibs).
# <public headers> A list of public header dirs (as passed to
# UsePublicHeaders).
local target = $(1) ;
local sources = $(2) ;
local dest = $(3) ;
local libraries = $(4) ;
local headerDirs = $(5) ;
local objects = [ FGristFiles $(sources:S=$(SUFOBJ)) ] ;
# Our Main replacement.
MainFromObjects $(target) : $(objects) ;
TestObjects $(sources) : $(headerDirs) ;
MakeLocate $(target) : [ FDirName $(OBOS_TEST_DIR) $(dest) ] ;
Depends $(target) : libcppunit.so ;
Depends obostests : $(target) ;
LinkSharedOSLibs $(target) : libcppunit.so $(libraries) ;
}
rule R5UnitTest
{
# R5UnitTest <target> : <sources> : <dest> : <libraries>
# Builds a unit test for an R5 module. "_r5" is appended to the object
# and the target name.
# <target> The name of the target.
# <sources> The list of sources.
# <dest> The directory for the target (as passed to FDirName).
# <libraries> A list of link libraries (as passed to LinkSharedOSLibs).
local target = $(1)_r5 ;
local sources = $(2) ;
local dest = $(3) ;
local libraries = $(4) ;
local objects = [ R5ObjectNames $(sources) ] ;
# Our Main replacement.
MainFromObjects $(target) : $(objects) ;
TestObjects $(sources) : : true ;
MakeLocate $(target) : [ FDirName $(OBOS_TEST_DIR) $(dest) ] ;
Depends $(target) : libcppunit.so ;
Depends r5tests : $(target) ;
LinkSharedOSLibs $(target) : libcppunit.so $(libraries) ;
}
rule R5ObjectNames
{
# R5ObjectNames <sources> ;
# Returns a list of gristed object names given a list of source file names.
# Moreover each object names gets "_r5" inserted before the object suffix.
local objects = $(1:S=)_r5 ;
return [ FGristFiles $(objects:S=$(SUFOBJ)) ] ;
}
rule R5Objects
{
# R5Objects <sources>
# Similar to Objects, but appends "_r5" to the object file names and
# removes `-nostdinc' from the CC and C++ flags to enable system headers.
# <sources> The source files.
# Remove `-nostdinc' from CCFLAGS and C++FLAGS.
local oldCCFLAGS = $(CCFLAGS) ;
local oldC++FLAGS = $(C++FLAGS) ;
CCFLAGS = [ Filter $(CCFLAGS) : -nostdinc ] ;
C++FLAGS = [ Filter $(C++FLAGS) : -nostdinc ] ;
local sources = $(1) ;
local source ;
for source in [ FGristFiles $(sources) ]
{
local object = [ R5ObjectNames $(source) ] ;
Object $(object) : $(source) ;
LocalDepends obj : $(object) ;
}
# Reset CCFLAGS and C++FLAGS to original values.
CCFLAGS = $(oldCCFLAGS) ;
C++FLAGS = $(oldC++FLAGS) ;
}
rule TestObjects
{
# TestLib <sources> : <public headers> : <r5>
# Compiles objects for tests.
# <sources> The list of sources.
# <public headers> A list of public header dirs (as passed to
# UsePublicHeaders).
# <r5> If set, "_r5" is appended to the object file names and
# <public headers> is ignored. Furthermore the pre-processor macro
# TEST_R5 is defined, TEST_OBOS otherwise.
local sources = $(1) ;
local headerDirs = $(2) ;
local r5 = $(3) ;
local objects ;
# Turn optimization off.
if ! $(NO_TEST_DEBUG) {
local optim = $(OPTIM) ;
OPTIM = ;
}
SetupObjectsDir ;
# compile
if $(r5) {
SetupR5Includes ;
objects = [ R5ObjectNames $(sources) ] ;
R5Objects $(sources) ;
} else {
SetupIncludes ;
objects = [ FGristFiles $(sources:S=$(SUFOBJ)) ] ;
Objects $(sources) ;
}
# set headers/defines
UseCppUnitObjectHeaders $(sources) : $(objects) ;
if $(r5) {
ObjectsDefines $(objects) : TEST_R5 ;
} else {
UsePublicObjectHeaders $(sources) : $(headerDirs) : $(objects) ;
ObjectsDefines $(objects) : TEST_OBOS ;
}
if ! $(NO_TEST_DEBUG) {
# Turn debugging on. That is usually desired for test code.
ObjectCcFlags $(objects) : "-g" ;
ObjectC++Flags $(objects) : "-g" ;
# Turn optimization on again.
OPTIM = $(optim) ;
}
}
rule R5SharedLibraryNames
{
# R5SharedLibraryNames <sources> ;
# Returns a list of shared library names given a list of file names. NO
# GRISTING IS PERFORMED :-) However, each library names gets "_r5" inserted
# before the shared lib suffix.
return $(1:S=)_r5.so ;
}
rule SimpleTest
{
# UnitTest <target> : <sources> : <libraries>
# Builds a unit test for an OBOS module.
# <target> The name of the target.
# <sources> The list of sources.
# <dest> The directory for the target (as passed to FDirName).
# <libraries> A list of link libraries (as passed to LinkSharedOSLibs).
# <public headers> A list of public header dirs (as passed to
# UsePublicHeaders).
local target = $(1) ;
local sources = $(2) ;
local libraries = $(3) ;
local relPath = [ FRelPath src tests : $(SUBDIR_TOKENS) ] ;
# Turn optimization off.
if ! $(NO_TEST_DEBUG) {
local optim = $(OPTIM) ;
OPTIM = ;
}
SetupIncludes ;
SetupObjectsDir ;
MakeLocateObjects $(sources) ;
Main $(target) : $(sources) ;
MakeLocate $(target) : [ FDirName $(OBOS_TEST_DIR) $(relPath) ] ;
Depends obostests : $(target) ;
LinkSharedOSLibs $(target) : $(libraries) ;
ObjectsDefines $(sources) : TEST_OBOS ;
if ! $(NO_TEST_DEBUG) {
# Turn debugging on. That is usually desired for test code.
ObjectCcFlags $(sources) : "-g" ;
ObjectC++Flags $(sources) : "-g" ;
# Turn optimization on again.
OPTIM = $(optim) ;
}
}
rule Addon
{
# Addon <name> : <relpath> : <sources> : <is executable> : <libraries> ;
# <name>: Name of the add-on.
# <relpath>: Path where the add-on shall live relative to the add-on dir.
# <sources>: Source files.
# <is executable>: true, if the target shall be executable as well.
# <libraries>: Libraries to be linked against.
local isExecutable = $(4) ;
SetupIncludes ;
SetupObjectsDir ;
Main $(1) : $(3) ;
# Create output dir path for addon
local targetdir;
targetdir = [ FDirName $(OBOS_ADDON_DIR) $(2) ] ;
MakeLocate $(1) : $(targetdir) ;
local linkFlags = -Xlinker -soname=\"$(1)\" ;
if $(isExecutable) != true {
linkFlags = -nostart $(linkFlags) ;
}
LINKFLAGS on $(1) = [ on $(1) return $(LINKFLAGS) ] $(linkFlags) ;
LinkSharedOSLibs $(1) : $(5) ;
}
rule R5KernelAddon
{
# R5KernelAddon <name> : <relpath> : <sources> : <static-libraries> ;
local sources = $(3) ;
Addon $(1) : $(2) : $(3) ;
ObjectCcFlags $(sources) : -D_KERNEL_MODE=1 -no-fpic ;
ObjectC++Flags $(sources) : -D_KERNEL_MODE=1 -no-fpic -fno-exceptions ;
LINKFLAGS on $(1) = [ on $(1) return $(LINKFLAGS) ] -nostdlib ;
LinkSharedOSLibs $(1) : $(4) /boot/develop/lib/x86/_KERNEL_ ;
}
rule Translator
{
# Translator <name> : <sources> : <libraries> ;
SetupIncludes ;
SetupObjectsDir ;
Main $(1) : $(2) ;
LinkSharedOSLibs $(1) : $(3) ;
# Create output dir path for translator
local targetdir;
targetdir = [ FDirName $(OBOS_ADDON_DIR) Translators ] ;
MakeLocate $(1) : $(targetdir) ;
}
rule ScreenSaver
{
# ScreenSaver <name> : <sources> : <libraries> ;
Addon $(1) : screen_savers : $(2) : false : $(3) ;
}
rule MakeLocateObjects
{
# MakeLocateObjects <sources_or_objects> ;
local _objs = [ FGristFiles $(1:S=$(SUFOBJ)) ] ;
for o in $(_objs)
{
local dir = $(o:D) ;
if $(dir) {
MakeLocate $(o) : [ FDirName $(LOCATE_TARGET) $(dir) ] ;
} else {
MakeLocate $(o) : $(LOCATE_TARGET) ;
}
}
}
rule StaticLibrary
{
# StaticLibrary <name> : <sources> [ : <target dir> ] ;
# Creates a static library from sources.
# <name>: Basename of the library, without leading "lib" and trailing ".a".
# Grist is allowed -- it will be re-prepended after constructing
# the complete library name.
# <source>: List of source files.
# <target dir>: Directory into which the library shall be placed. Defaults
# to the objects directory for this subdir. If
# STATIC_LIBRARY_DIR is supplied (the literal string)
# the standard directory for static libs is used, otherwise
# the parameter is interpreted as directory path.
#
local lib = lib$(1:B)$(SUFLIB) ;
lib = $(lib:G=$(1:G)) ;
SetupIncludes ;
SetupObjectsDir ;
MakeLocateObjects $(2) ;
Library $(lib) : $(2) ;
local targetDir = $(3) ;
if $(targetDir) {
if $(targetDir) = STATIC_LIBRARY_DIR {
targetDir = $(OBOS_STLIB_DIR) ;
}
MakeLocate $(lib) : $(targetDir) ;
} else {
# nothing to do, since the Library rule already located the library
# in $(LOCATE_TARGET)
}
# If KEEPOBJS is set, Library doesn't make the library depend on
# `lib'.
if $(KEEPOBJS) {
LocalDepends lib : $(lib) ;
}
}
rule R5KernelStaticLibrary
{
# R5KernelStaticLibrary <name> : <sources> ;
local lib = lib$(1)$(SUFLIB) ;
local sources = $(2) ;
SetupIncludes ;
SetupObjectsDir ;
MakeLocateObjects $(sources) ;
Library $(lib) : $(sources) ;
ObjectCcFlags $(sources) : -D_KERNEL_MODE=1 -no-fpic ;
ObjectC++Flags $(sources) : -D_KERNEL_MODE=1 -no-fpic -fno-exceptions ;
}
rule MergeObjectFromObjects
{
# MergeObjectFromObjects <name> : <objects> : <other objects> ;
# Merges object files to an object file.
# <name>: Name of the object file to create. No grist will be added.
# <objects>: Object files to be merged. Grist will be added.
# <other objects>: Object files or static libraries to be merged. No grist
# will be added.
#
local objects = [ FGristFiles $(2) ] ;
MakeLocate $(1) : $(LOCATE_TARGET) ;
Depends $(1) : $(objects) ;
Depends $(1) : $(3) ;
LINK on $(1) = ld ;
MergeObjectFromObjects1 $(1) : $(objects) $(3) ;
}
actions MergeObjectFromObjects1
{
$(LINK) -r $(2) -o $(1) ;
}
rule MergeObject
{
# MergeObject <name> : <sources> : <other objects> ;
# Compiles source files and merges the object files to an object file.
# <name>: Name of the object file to create. No grist will be added.
# <sources>: Sources to be compiled. Grist will be added.
# <other objects>: Object files or static libraries to be merged. No grist
# will be added.
#
SetupIncludes ;
SetupObjectsDir ;
MakeLocateObjects $(2) ;
Objects $(2) ;
MergeObjectFromObjects $(1) : $(2:S=$(SUFOBJ)) : $(3) ;
}
rule SharedLibraryFromObjects
{
# SharedLibraryFromObjects <name> : <objects> : <libraries> ;
local _lib = lib$(1:B).so ;
_lib = $(_lib:G=$(1:G)) ;
MainFromObjects $(_lib) : $(2) ;
MakeLocate $(_lib) : $(OBOS_SHLIB_DIR) ;
LINKFLAGS on $(_lib) = [ on $(_lib) return $(LINKFLAGS) ]
-nostart -Xlinker -soname=\"$(_lib)\" ;
LinkSharedOSLibs $(_lib) : $(3) ;
}
rule SharedLibrary
{
# SharedLibrary <name> : <sources> : <libraries> ;
SetupIncludes ;
SetupObjectsDir ;
MakeLocateObjects $(2) ;
Objects $(2) ;
SharedLibraryFromObjects $(1) : $(2:S=$(SUFOBJ)) : $(3) ;
}
rule LinkSharedOSLibs
{
# LinkSharedOSLibs <name> : <libs> ;
# Valid elements for <libs> are e.g. "be" or "libopenbeos.so" or
# "/boot/.../libfoo.so". If the basename starts with "lib" or the thingy
# has a dirname or grist, it is added to the NEEDLIBS variable (i.e. the
# file will be bound!), otherwise it is prefixed "-l" and added to
# LINKLIBS. If you want to specify a target that isn't a library and
# also has neither grist nor a dirname, you can prepend "<nogrist>" as
# grist; it will be stripped by this rule.
for i in $(>)
{
local isfile = ;
if $(i:D) || $(i:G) {
isfile = true ;
if $(i:G) = <nogrist> {
i = $(i:G=) ;
}
} else {
switch $(i:B)
{
# XXX: _APP_ and _KERNEL_ should not be needed for ELF.
case _APP_ : isfile = true ;
case _KERNEL_ : isfile = true ;
case lib* : isfile = true ;
case * : isfile = ;
}
if ! $(isfile) && ( $(i:S) = .so || $(i:S) = .a ) {
isfile = true ;
}
}
if $(isfile) {
NEEDLIBS on $(1) = [ on $(1) return $(NEEDLIBS) ] $(i) ;
Depends $(1) : $(i) ;
} else {
LINKLIBS on $(1) = [ on $(1) return $(LINKLIBS) ] -l$(i) ;
}
}
}
rule AddResources
{
# AddResources <name> : <resourcefiles> ;
local resfiles = [ FGristFiles $(2) ] ;
SEARCH on $(resfiles) += $(SEARCH_SOURCE) ;
for file in $(resfiles) {
if $(file:S) = .rdef {
local rdef = $(file) ;
file = $(rdef:S=.rsrc) ;
ResComp $(file) : $(rdef) ;
}
RESFILES on $(1) += $(file) ;
}
}
rule ResComp
{
# ResComp <resource file> : <rdef file> ;
#
# <resource file> and <rdef file> must be gristed.
SetupObjectsDir ;
SEARCH on $(2) += $(SEARCH_SOURCE) ;
MakeLocate $(1) : $(LOCATE_TARGET) ;
Depends $(1) : $(2) rc ;
LocalClean clean : $(1) ;
ResComp1 $(1) : rc $(2) ;
}
actions ResComp1
{
$(2[1]) -o $(1) $(2[2-])
}
rule ObjectsDefines
{
# Like ObjectDefines, but allows multiple files to be supplied
local file ;
for file in $(1) {
ObjectDefines $(file) : $(2) ;
}
}
rule SourceHdrs
{
# SourceHdrs <sources> : <headers> [ : <gristed objects> ] ;
#
# Is a wrapper for ObjectHdrs, that passes <sources> and <headers> or,
# if supplied <objects> and <headers>, and also adjusts HDRSEARCH (not
# done by ObjectHdrs).
local sources = [ FGristFiles $(1) ] ;
local headers = $(2) ;
local objects = $(3) ;
local file ;
if $(objects) {
for file in $(objects) {
ObjectHdrs $(file) : $(headers) ;
# also reformat the assembler headers
ASHDRS on $(file) = [ FIncludes $(SEARCH_SOURCE) $(SUBDIRHDRS)
[ on $(file) return $(HDRS) ] ] ;
}
} else {
for file in $(sources:S=$(SUFOBJ)) {
ObjectHdrs $(file) : $(headers) ;
# also reformat the assembler headers
ASHDRS on $(file) = [ FIncludes $(SEARCH_SOURCE) $(SUBDIRHDRS)
[ on $(file) return $(HDRS) ] ] ;
}
}
# Also add the header search dirs to HDRSEARCH. Note, that these dirs
# will be listed after the STDHDRS (if any), but that's better than not
# being listed at all.
HDRSEARCH on $(sources) += $(headers) ;
}
rule PublicHeaders
{
# PublicHeaders <group list>
#
# Returns the directory names for the public header dirs identified by
# <group list>.
local list = $(1) ;
local dirs = [ FDirName $(OBOS_TOP) headers os ] ;
for i in $(list) {
dirs += [ FDirName $(OBOS_TOP) headers os $(i) ] ;
}
return $(dirs) ;
}
rule PrivateHeaders
{
# PrivateHeaders <group list>
#
# Returns the directory names for the private header dirs identified by
# <group list>.
local list = $(1) ;
local dirs ;
for i in $(list) {
dirs += [ FDirName $(OBOS_TOP) headers private $(i) ] ;
}
return $(dirs) ;
}
rule LibraryHeaders
{
# LibraryHeaders <group list>
#
# Returns the directory names for the library header dirs identified by
# <group list>.
local list = $(1) ;
local dirs ;
for i in $(list) {
dirs += [ FDirName $(OBOS_TOP) headers libs $(i) ] ;
}
return $(dirs) ;
}
rule ArchHeaders
{
# usage: ArchHeaders <arch> ;
#
# <arch> specifies the architecture (e.g. x86).
return [ FDirName $(OBOS_TOP) headers private kernel arch $(1) ] ;
}
rule UsePublicHeaders
{
# UsePublicHeaders <group list> ;
#
# Adds the public C header dirs given by <group list> to the header search
# dirs of the subdirectory.
# NOTE: This rule must be invoked *before* the rule that builds the
# objects.
UseHeaders [ PublicHeaders $(1) ] ;
}
rule UsePublicObjectHeaders
{
# UsePublicObjectHeaders <sources> : <group list> [ : <objects> ] ;
#
# Adds the public C header dirs given by <group list> to the header search
# dirs of either the object targets of <sources> or if supplied to
# <objects>. Also adjusts HDRSEARCH of <sources>.
# NOTE: This rule must be invoked *after* the rule that builds the objects.
SourceHdrs $(1) : [ PublicHeaders $(2) ] : $(3) ;
}
rule UsePrivateHeaders
{
# UsePrivateHeaders <group list> ;
#
# Adds the private C header dirs given by <group list> to the header search
# dirs of the subdirectory.
# NOTE: This rule must be invoked *before* the rule that builds the objects.
UseHeaders [ PrivateHeaders $(1) ] ;
}
rule UsePrivateObjectHeaders
{
# UsePrivateObjectHeaders <sources> : <group list> [ : <objects> ] ;
#
# Adds the private C header dirs given by <group list> to the header search
# dirs of either the object targets of <sources> or if supplied to
# <objects>. Also adjusts HDRSEARCH of <sources>.
# NOTE: This rule must be invoked *after* the rule that builds the objects.
SourceHdrs $(1) : [ PrivateHeaders $(2) ] : $(3) ;
}
rule UseHeaders
{
# UseHeaders <headers> ;
#
# Adds the C header dirs <headers> to the header search
# dirs of the subdirectory.
# NOTE: This rule must be invoked *before* the rule that builds the objects.
local header ;
for header in $(1) {
SubDirHdrs $(header) ;
}
}
rule UseCppUnitHeaders
{
SubDirHdrs [ FDirName $(OBOS_TOP) headers tools cppunit ] ;
}
rule UseCppUnitObjectHeaders
{
# UseCppUnitObjectHeaders <sources> [ : <objects> ] ;
SourceHdrs $(1) : [ FDirName $(OBOS_TOP) headers tools cppunit ] : $(2) ;
}
rule UseArchHeaders
{
# usage: UseArchHeaders <arch> ;
#
# <arch> specifies the architecture (e.g. x86).
# NOTE: This rule must be invoked *before* the rule that builds the objects.
local headers = [ ArchHeaders $(1) ] ;
local opt = -D$(OBOS_TARGET_DEFINE) ;
SubDirCcFlags $(opt) ;
SubDirC++Flags $(opt) ;
HDRS += $(headers) ;
}
rule UseArchObjectHeaders
{
# usage: UseArchObjectHeaders <sources> : <arch> : [ <objects> ] ;
#
# <arch> specifies the architecture (e.g. x86).
# <sources_or_objects> Source or object files.
# NOTE: This rule must be invoked *after* the rule that builds the objects.
local sources = $(1) ;
local headers = [ ArchHeaders $(2) ] ;
local objects = $(3) ;
local targets ;
if $(objects) {
targets = $(objects) ;
} else {
targets = [ FGristFiles $(sources:S=$(SUFOBJ)) ] ;
}
local opt = -D$(OBOS_TARGET_DEFINE) ;
ObjectCcFlags $(targets) : $(opt) ;
ObjectC++Flags $(targets) : $(opt) ;
SourceHdrs $(sources) : $(headers) : $(objects) ;
}
rule UsePosixHeaders
{
# XXX changed to do nothing
}
rule UsePosixObjectHeaders
{
# UsePosixObjectHeaders <sources> [ : <objects> ] ;
#
# Adds the POSIX header dir to the header search
# dirs of either the object targets of <sources> or if supplied to
# <objects>. Also adjusts HDRSEARCH of <sources>.
# NOTE: This rule must be invoked *after* the rule that builds the objects.
SourceHdrs $(1) : [ FDirName $(OBOS_TOP) headers posix ] : $(2) ;
}
rule UseLibraryHeaders
{
# UseLibraryHeaders <group list> ;
#
# Adds the library header dirs given by <group list> to the header search
# dirs of the subdirectory.
# NOTE: This rule must be invoked *before* the rule that builds the objects.
UseHeaders [ LibraryHeaders $(1) ] ;
}
rule SplitPath
{
# SplitPath <path> ;
# Decomposes a path into its components.
local path = $(1:G=) ;
local components ;
# $(path:D) for "/" is "/". Therefore the second condition.
while $(path:D) && $(path:D) != $(path)
{
# Note: $(path:B) returns "." for "..", but $(path:D=) is fine.
components = $(path:D=) $(components) ;
path = $(path:D) ;
}
components = $(path) $(components) ;
return $(components) ;
}
rule PrependObjectHdrs
{
# PrependObjectHdrs <objects_or_sources> : <dirs> ;
# Prepends <dirs> to the list of header search dirs of the objects
# specified by <objects_or_sources>. The HDRS variable will not be
# changed, only CCHDRS.
# Note: A subsequent ObjectHdrs invocation will therefore undo the
# effect of this rule.
# NOTE: This is a hack.
local objects = [ FGristFiles $(1:S=$(SUFOBJ)) ] ;
local dirs = $(2) ;
for object in $(objects) {
# Don't change HDRS to avoid screwing up the header scanning.
PREPENDED_HDRS on $(object)
= $(dirs) [ on $(object) return $(PREPENDED_HDRS) ] ;
CCHDRS on $(object)
= [ FIncludes [ on $(object) return $(PREPENDED_HDRS) $(HDRS) ] ] ;
}
}
rule SymLink
{
# SymLink <target> : <source> : <makeDefaultDependencies> ;
# Links <target> to <source>.
# <source> is the exact link contents. No binding is done.
# <makeDefaultDependencies> If true, <target> will be made a dependency
# of the `all' pseudo target, i.e. it will be made by default, and removed
# on `jam clean'.
local target = $(1) ;
local source = $(2) ;
local makeDefaultDependencies = $(3) ;
if ! $(makeDefaultDependencies) {
makeDefaultDependencies = true ;
}
LINKCONTENTS on $(target) = $(source) ;
SymLink1 $(target) ;
if $(makeDefaultDependencies) = true {
LocalDepends files : $(target) ;
LocalClean clean : $(target) ;
}
}
actions SymLink1
{
$(RM) "$(1)" && $(LN) -s "$(LINKCONTENTS)" "$(1)"
}
rule RelSymLink
{
# RelSymLink <link> : <link target> : <makeDefaultDependencies> ;
# Creates a relative symbolic link from <link> to <link target>.
# <link> and <link target> can be usual targets. They may have a grist
# and don't need to have any dirname. Their LOCATE variables are used to
# find their locations.
# <makeDefaultDependencies> If true (which is the default), <link> will be
# made a dependency of the `files' pseudo target, i.e. it will be made by
# default, and removed on `jam clean'.
local target = $(1) ;
local source = $(2) ;
local makeDefaultDependencies = $(3) ;
local targetDir = [ on $(target) FDirName $(LOCATE[1]) $(target:D) ] ;
local sourceDir = [ on $(source) FDirName $(LOCATE[1]) $(source:D) ] ;
local sourcePath = $(source:G=) ;
sourcePath = $(sourcePath:D=$(sourceDir)) ;
local targetDirComponents = [ SplitPath $(targetDir) ] ;
local sourceComponents = [ SplitPath $(sourcePath) ] ;
SymLink $(target)
: [ FRelPath $(targetDirComponents) : $(sourceComponents) ]
: $(makeDefaultDependencies) ;
NOUPDATE $(target) ;
Depends $(target) : $(source) ;
}
rule AbsSymLink
{
# AbsSymLink <link> : <link target> : <link dir>
# : <makeDefaultDependencies> ;
# Creates an absolute symbolic link from <link> to <link target>.
# <link> and <link target> must be usual targets. If <link dir> is
# given, then it is set as LOCATE directory on <link>.
# <makeDefaultDependencies> If true (which is the default), <link> will be
# made a dependency of the `files' pseudo target, i.e. it will be made by
# default, and removed on `jam clean'.
local makeDefaultDependencies = $(4) ;
if ! $(makeDefaultDependencies) {
makeDefaultDependencies = true ;
}
Depends $(1) : $(2) ;
if $(3) {
MakeLocate $(1) : $(3) ;
}
SEARCH on $(2) += $(SEARCH_SOURCE) ;
if $(makeDefaultDependencies) = true {
LocalDepends files : $(1) ;
LocalClean clean : $(1) ;
}
}
actions AbsSymLink
{
target="$(2)"
case "$target" in
/*) ;;
*) target=`pwd`/"$target";;
esac
$(RM) "$(1)" && $(LN) -s "$target" "$(1)"
}
rule OBOSInstall
{
# Usage: OBOSInstall <[ install [ and uninstall ] pseudotarget ]>
# : <directory> : <sources to install>
# : [ <installgrist> ] : [ <install rule> ] ;
local install = $(1[1]) ;
install ?= install ;
local uninstall = $(1[2]) ;
uninstall ?= un$(install) ;
local dir = $(2) ;
local sources = $(3) ;
local installgrist = $(4) ;
installgrist ?= $(INSTALLGRIST) ;
local installRule = $(5) ;
installRule ?= Install ;
local targets = $(sources:G=$(installgrist)) ;
NotFile $(install) ;
NotFile $(uninstall) ;
Depends $(install) : $(targets) ;
Clean $(uninstall) : $(targets) ;
SEARCH on $(sources) += $(SEARCH_SOURCE) ;
MakeLocate $(targets) : $(dir) ;
local source ;
for source in $(sources) {
local target = $(source:G=$(installgrist)) ;
Depends $(target) : $(source) ;
$(installRule) $(target) : $(source) ;
if [ on $(target) return $(MODE) ] {
Chmod $(target) ;
}
if $(OWNER) && $(CHOWN) {
Chown $(target) ;
OWNER on $(target) = $(OWNER) ;
}
if $(GROUP) && $(CHGRP) {
Chgrp $(target) ;
GROUP on $(target) = $(GROUP) ;
}
}
}
rule InstallAbsSymLinkAdapter
{
# InstallAbsSymLinkAdapter <link> : <link target>
if ! [ on $(2) return $(TARGET) ] {
TARGET on $(2) = [ on $(2) return $(SEARCH) ] ;
}
AbsSymLink $(1) : $(2) : : false ;
}
rule OBOSInstallAbsSymLink
{
# Usage: OBOSInstallAbsSymLink <[ install [ and uninstall ] pseudotarget ]>
# : <directory> : <sources to install>
# : [ <installgrist> ] ;
OBOSInstall $(1) : $(2) : $(3) : $(4) : InstallAbsSymLinkAdapter ;
}
rule InstallRelSymLinkAdapter
{
# InstallRelSymLinkAdapter <link> : <link target>
if ! [ on $(2) return $(TARGET) ] {
TARGET on $(2) = [ on $(2) return $(SEARCH) ] ;
}
RelSymLink $(1) : $(2) : false ;
}
rule OBOSInstallRelSymLink
{
# Usage: OBOSInstallRelSymLink <[ install [ and uninstall ] pseudotarget ]>
# : <directory> : <sources to install>
# : [ <installgrist> ] ;
OBOSInstall $(1) : $(2) : $(3) : $(4) : InstallRelSymLinkAdapter ;
}
#-------------------------------------------------------------------------------
# Low-level OBOS utility rules
#-------------------------------------------------------------------------------
rule FObjectsDir
{
# FObjectsDir <subdir tokens>
#
# Returns the output directory for object files the specified
# subdirectory.
#
# <subdir tokens>: The tokens of the subdir relative to the top.
#
return [ FDirName $(OBOS_OBJECT_TARGET) $(1[2-]) ] ;
}
rule FCurrentObjectsDir
{
# FCurrentObjectsDir
#
# Returns the output directory for object files for the current
# subdirectory.
return [ FObjectsDir $(SUBDIR_TOKENS) ] ;
}
rule SetupObjectsDir
{
LOCATE_TARGET = [ FCurrentObjectsDir ] ;
LOCATE_SOURCE = $(LOCATE_TARGET) ;
SEARCH_SOURCE = [ Filter $(SEARCH_SOURCE) : $(LOCATE_TARGET) ]
$(LOCATE_TARGET) ;
}
#-------------------------------------------------------------------------------
# Link rule/action are overwritten as they don't handle linking files who's name
# contain spaces very well. Also adds resources and version to executable.
#-------------------------------------------------------------------------------
rule Link
{
# Note: RESFILES must be set before invocation.
MODE on $(<) = $(EXEMODE) ;
on $(1) XRes $(1) : $(RESFILES) ;
Chmod $(<) ;
SetType $(1) ;
MimeSet $(1) ;
SetVersion $(1) ;
}
actions Link bind NEEDLIBS
{
$(LINK) $(LINKFLAGS) -o "$(1)" $(UNDEFS) "$(2)" "$(NEEDLIBS)" $(LINKLIBS) ;
}
rule LexC++
{
Depends $(1) : $(2) ;
MakeLocate $(1) : $(LOCATE_SOURCE) ;
LocalClean clean : $(1) ;
}
actions LexC++
{
$(LEX) -o$(1) $(2)
}
rule Bison
{
local _h ;
_h = $(1:S=.hpp) ;
MakeLocate $(<) $(_h) : $(LOCATE_SOURCE) ;
Depends $(<) $(_h) : $(>) ;
Bison1 $(<) $(_h) : $(>) ;
LocalClean clean : $(<) $(_h) ;
# make sure someone includes $(_h) else it will be
# a deadly independent target
Includes $(<) : $(_h) ;
}
actions Bison1
{
bison $(YACCFLAGS) -o $(1[1]) $(2)
[ -f $(1[1]).h ] && mv $(1[1]).h $(1[2]) || true
}
rule UnarchiveObjects
{
# UnarchiveObjects <target objects> : <static object>
MakeLocate $(1) : $(LOCATE_TARGET) ;
Depends $(2) : $(1) ;
SEARCH on $(2) = $(SEARCH_SOURCE) ;
}
actions UnarchiveObjects
{
cd $(1[1]:D)
ar -x "$(2)" $(1:B).o
cd -
}
# BeOS specific rules
rule XRes
{
# XRes <target> : <resource files>
if $(2)
{
Depends $(1) : $(2) ;
XRes1 $(1) : $(2) ;
}
}
rule XRes1 { }
rule SetVersion
{
# SetVersion <target>
}
rule SetType
{
# SetType <target>
}
rule MimeSet
{
# SetType <target>
}
if $(OS) = BEOS
{
actions XRes1
{
xres -o "$(1)" "$(2)" ;
}
actions SetVersion
{
setversion "$(1)" -system $(OBOS_BUILD_VERSION) -short "$(OBOS_BUILD_DESCRIPTION)" ;
}
actions SetType
{
settype -t $(OBOS_TARGET_TYPE) "$(1)" ;
}
actions MimeSet
{
mimeset -f "$(1)" ;
}
} # if BEOS
rule assemble
{
Depends $(<) : $(>) ;
ASFLAGS on $(<) += $(ASFLAGS) $(SUBDIRASFLAGS) ;
ASHDRS on $(<) = [ FIncludes $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ] ;
}
actions assemble
{
$(CC) -c "$(2)" -O2 $(ASFLAGS) -D_ASSEMBLER $(KERNEL_CCFLAGS) $(ASHDRS) -o "$(1)" ;
}
# Overridden to allow spaces in file names.
actions Chmod1
{
$(CHMOD) "$(MODE)" "$(1)"
}
# Overridden to allow spaces in file names.
actions piecemeal together existing Clean
{
$(RM) "$(>)"
}
rule ObjectReference
{
# ObjectReference <reference object> : <source object>
# Makes <reference object> refer to the same file as <source object>.
# The filenames must of course be identical.
# <source object> must have already been LOCATEd.
local ref = $(1) ;
local source = $(2) ;
if $(ref) != $(source) {
Depends $(ref) : $(source) ;
LOCATE on $(ref) = [ on $(source) return $(LOCATE) ] ;
}
}
rule ObjectReferences
{
# ObjectReferences <source objects>
# Creates local references to <source objects>, i.e. identifiers with the
# current grist referring to the same files. <source objects> must have
# already been LOCATEd.
local source ;
for source in $(1) {
ObjectReference [ FGristFiles $(source) ] : $(source) ;
}
}
rule Filter
{
# Filter <list> : <excludes> ;
# Removes all occurrences of <excludes> in <list>.
local list = $(1) ;
local excludes = $(2) ;
local newList ;
local item ;
for item in $(list) {
local skip ;
local exclude ;
for exclude in $(excludes) {
if $(item) = $(exclude) {
skip = true ;
}
}
if ! $(skip) {
newList += $(item) ;
}
}
return $(newList) ;
}
## Kernel stuff!
rule SetupKernel
{
# Usage SetupKernel <sources_or_objects> : <extra_cc_flags>;
#
# <sources_or_objects> - Ideally sources, otherwise HDRSEARCH can not be
# set for the sources and the sources some header
# dependencies might be missing.
local sources = [ FGristFiles $(1) ] ;
local _objs = $(sources:S=$(SUFOBJ)) ;
#Setup Kernel header directories
local public_kernel_includes = add-ons/file_system add-ons/graphics app device drivers kernel storage support ;
local private_kernel_includes = $(DOT) kernel libroot kernel/boot/platform/$(OBOS_BOOT_PLATFORM) ;
# Use posix headers directory
local headers = [ FDirName $(OBOS_TOP) headers posix ] ;
# Use public OS header directories
headers += [ PublicHeaders $(public_kernel_includes) ] ;
# Use private directories
headers += [ PrivateHeaders $(private_kernel_includes) ] ;
# The platform dependent headers.
headers += $(PLATFORM_HEADERS) ;
SourceHdrs $(sources) : $(headers) ;
UseArchObjectHeaders $(sources) : $(OBOS_ARCH) ;
local object ;
for object in $(_objs) {
ObjectCcFlags $(object) : $(KERNEL_CCFLAGS) $(2) ;
ObjectC++Flags $(object) : $(KERNEL_C++FLAGS) $(2) ;
}
}
rule KernelObjects
{
SetupObjectsDir ;
Objects $(1) ;
SetupKernel $(1) : $(2) ;
}
rule KernelLd
{
# KernelLd <name> : <objs> : <linkerscript> : <args> : <gcc_off> : <config_section> ;
SetupObjectsDir ;
LINK on $(1) = ld ;
LINKFLAGS on $(1) = $(4) ;
if $(3) { LINKFLAGS on $(1) += --script=$(3) ; }
# Remove any preset LINKLIBS
LINKLIBS on $(1) = ;
# Show that we depend on the libraries we need
LocalClean clean : $(1) ;
LocalDepends all : $(1) ;
Depends $(1) : $(2) ;
if $(6) {
for i in $(6) {
KernelConfigSection $(i) : elf32 : $(1) ;
}
}
MakeLocate $(1) : $(LOCATE_TARGET) ;
# Add the platform specific static libs (libgcc.a).
if ! $(5) {
LINKLIBS on $(1) += $(PLATFORM_LINKLIBS) ;
}
SetupKernel $(2) ;
}
actions KernelLd
{
$(LINK) $(LINKFLAGS) -o "$(1)" "$(2)" $(LINKLIBS) ;
}
rule KernelAddon
{
# KernelAddon <name> : <relpath> : <sources> : <static-libraries> ;
local sources = $(3) ;
SetupObjectsDir ;
Addon $(1) : $(2) : $(sources) ;
ObjectCcFlags $(sources) : -D_KERNEL_MODE=1 -no-fpic ;
ObjectC++Flags $(sources) : -D_KERNEL_MODE=1 -no-fpic -fno-exceptions ;
LINKFLAGS on $(1) = [ on $(1) return $(LINKFLAGS) ] -nostdlib ;
LinkSharedOSLibs $(1) : $(4) $(OBOS_TOP)/objects/$(OBOS_ARCH).$(OBOS_VERSION)/kernel/kernel.so ;
# ToDo this has to be changed!
SetupKernel $(sources) ;
}
rule KernelMergeObject
{
# KernelMergeObject <name> : <sources> : <extra CFLAGS> : <other objects> ;
# Compiles source files and merges the object files to an object file.
# <name>: Name of the object file to create. No grist will be added.
# <sources>: Sources to be compiled. Grist will be added.
# <extra CFLAGS>: Additional flags for compilation.
# <other objects>: Object files or static libraries to be merged. No grist
# will be added.
#
SetupObjectsDir ;
MakeLocateObjects $(2) ;
Objects $(2) ;
MergeObjectFromObjects $(1) : $(2:S=$(SUFOBJ)) : $(4) ;
SetupKernel $(2) : $(3) ;
}
rule KernelStaticLibrary
{
# Usage KernelStaticLibrary <name> : <sources> : <extra cc flags> ;
# This is designed to take a set of sources and libraries and create
# a file called lib<name>.a
SetupObjectsDir ;
MakeLocateObjects $(2) ;
Library $(1) : $(2) ;
SetupKernel $(2) : $(3) ;
}
rule KernelStaticLibraryObjects
{
# Usage KernelStaticLibrary <name> : <sources> ;
# This is designed to take a set of sources and libraries and create
# a file called <name>
SetupObjectsDir ;
# Show that we depend on the libraries we need
LocalClean clean : $(1) ;
LocalDepends all : $(1) ;
Depends $(1) : $(2) ;
MakeLocate $(1) : $(LOCATE_TARGET) ;
SetupKernel $(2) ;
}
actions KernelStaticLibraryObjects
{
ar -r "$(1)" "$(2)" ;
}
rule BuildPlatformMain
{
# Usage BuildPlatformMain <target> : <sources> ;
SetupObjectsDir ;
SetupDefaultIncludes ;
# Remove `-nostdinc' from CCFLAGS and C++FLAGS.
local oldCCFLAGS = $(CCFLAGS) ;
local oldC++FLAGS = $(C++FLAGS) ;
CCFLAGS = [ Filter $(CCFLAGS) : -nostdinc ] ;
C++FLAGS = [ Filter $(C++FLAGS) : -nostdinc ] ;
Main $(1) : $(2) ;
# Reset CCFLAGS and C++FLAGS to original values.
CCFLAGS = $(oldCCFLAGS) ;
C++FLAGS = $(oldC++FLAGS) ;
}
rule BuildPlatformTest
{
# Usage BuildPlatformTest <target> : <sources> ;
local target = $(1) ;
local sources = $(2) ;
BuildPlatformMain $(target) : $(sources) ;
local relPath ;
if [ FIsPrefix src tests : $(SUBDIR_TOKENS) ] {
relPath = $(SUBDIR_TOKENS[3-]) ;
} else {
relPath = $(SUBDIR_TOKENS[2-]) ;
}
MakeLocate $(target) : [ FDirName $(OBOS_TEST_DIR) $(relPath) ] ;
}
rule KernelConfigSection
{
# KernelConfigSection <section> : <type> : <file> ;
SECTION_NAMES on $(OBOS_KERNEL_CONFIG) += $(1) ;
SECTION_TYPES on $(OBOS_KERNEL_CONFIG) += $(2) ;
SECTION_FILES on $(OBOS_KERNEL_CONFIG) += $(3) ;
Depends $(OBOS_KERNEL_CONFIG) : $(3) ;
}
rule WriteKernelConfig
{
# usage: WriteKernelConfig <target> ;
LocalDepends files : $(1) ;
MakeLocate $(1) : $(OBOS_OBJECT_TARGET) ;
LocalClean clean : $(1) ;
}
actions WriteKernelConfig bind SECTION_FILES
{
target="$(1)"
echo "# OpenBeOS Kernel Config File" > "$target"
echo "# Automatically generated - do not edit!" >> "$target"
count=0
for section in "$(SECTION_NAMES)" ; do
count=`expr $count + 1`
eval section$count="$section"
done
i=1
for type in "$(SECTION_TYPES)" ; do
eval type$i="$type"
i=`expr $i + 1`
done
i=1
for file in "$(SECTION_FILES)" ; do
eval file$i="$file"
i=`expr $i + 1`
done
for i in `seq $count` ; do
eval section="\$section$i"
eval type="\$type$i"
eval file="\$file$i"
echo "" >> "$target"
echo "["$section"]" >> "$target"
echo "type="$type >> "$target"
case "$file" in
/*) ;;
*) file=`pwd`/"$file";;
esac
echo "file="$file >> "$target"
done
}
rule BuildKernel
{
# Usage BuildKernel <target> : <config_file> ;
local kernel = $(1) ;
local configFile = $(2) ;
local bootmaker = bootmaker ;
LocalDepends all : $(kernel) ;
Depends $(kernel) : $(configFile) $(bootmaker) ;
LocalClean clean : $(kernel) ;
MakeLocate $(kernel) : $(LOCATE_TARGET) ;
BOOT_MAKER on $(kernel) = $(bootmaker) ;
}
actions BuildKernel bind BOOT_MAKER
{
"$(BOOT_MAKER)" --strip-debug --strip-binary strip "$(2)" -o "$(1)" ;
echo ""
echo "Kernel linked!"
echo ""
}
rule KernelFloppyImage
{
# Usage KernelFloppyImage <target> : <kernel> : <bootblock> ;
local floppy = $(1) ;
local kernel = $(2) ;
local bootblock = $(3) ;
local makeflop = makeflop ;
LocalDepends all : $(floppy) ;
Depends $(floppy) : $(kernel) $(bootblock) $(makeflop) ;
LocalClean clean : $(floppy) ;
MakeLocate $(floppy) : $(OBOS_OBJECT_TARGET) ;
BOOT_BLOCK on $(floppy) = $(bootblock) ;
MAKE_FLOP on $(floppy) = $(makeflop) ;
}
# This may be a bit verbose, but I think it's useful to show what's
# going on, at least in this early stage of development.
actions KernelFloppyImage bind BOOT_BLOCK bind MAKE_FLOP
{
"$(MAKE_FLOP)" "-p $(shell expr 18 \* 2 \* 512)" "$(BOOT_BLOCK)" "$(2)" "$(1)" ;
echo ""
echo "*************************************************"
echo "* Kernel build completed! *"
echo "* Boot image for a 1.44M floppy created *"
echo "*************************************************"
echo ""
echo "Floppy image is $(1)"
echo "The following command will write it to a floppy on BeOS"
echo " dd if=$(1) of=/dev/disk/floppy/raw bs=18k"
echo "Alternatively you can run"
echo " ./configure --floppy /dev/disk/floppy/raw"
echo "once and build + write the image subsequently via"
echo " jam installfloppy"
echo ""
}
rule InstallFloppy
{
# InstallFloppy <target> : <floppy>
# "dd"s <floppy> to $(FLOPPY_PATH).
local target = $(1) ;
local floppy = $(2) ;
NotFile $(target) ;
Always $(target) ;
Depends $(target) : $(floppy) ;
}
actions InstallFloppy
{
if [ -z $(FLOPPY_PATH) ] ; then
echo "Can't install floppy: FLOPPY_PATH not set."
echo "run: ./configure --floppy <floppy path>"
echo
exit 0
fi
dd if=$(2) of=$(FLOPPY_PATH) bs=18k
}
#-------------------------------------------------------------------------------
# FreeType 2 specific rules and variables
#-------------------------------------------------------------------------------
FT2_INCLUDE = [ FDirName $(OBOS_TOP) headers libs freetype2 ] ;
FT2_SRC = [ FDirName $(OBOS_TOP) src libs freetype2 ] ;
FT2_LIB = freetype ;
FT2_COMPONENTS ?= gzip # support for gzip-compressed files.
autohint # auto-hinter
base # base component (public APIs)
bdf # BDF font driver
cache # cache sub-system
cff # CFF/CEF font driver
cid # Postscript CID-keyed font driver
lzw # LZW routines
pcf # PCF font driver
pfr # PFR/TrueDoc font driver
psaux # Common Postscript routines module
pshinter # Postscript hinter module
psnames # Postscript names handling
raster # Monochrome rasterizer
smooth # Anti-aliased rasterizer
sfnt # SFNT-based format support routines
truetype # TrueType font driver
type1 # Postscript Type 1 font driver
type42 # Postscript Type 42 (embedded TrueType) driver
winfonts # Windows FON/FNT font driver
;
rule UseFreeTypeHeaders
{
SubDirHdrs $(FT2_INCLUDE) ;
}
rule UseFreeTypeObjectHeaders
{
# UseFreeTypeObjectHeaders <sources> [ : <objects> ] ;
SourceHdrs $(1) : $(FT2_INCLUDE) : $(2) ;
}
rule FT2_SubDir
{
# FT2_SubDir <dir>
# <dir>: Components of a directory in the original hierarchy.
local dir = $(1) ;
local topDir ;
switch $(dir[1])
{
case "include" : topDir = $(FT2_INCLUDE) ;
case src : topDir = $(FT2_SRC) ;
case * : ECHO "Unknown FreeType2 directory: " $(dir) ;
}
return [ FDirName $(topDir) $(dir[2-]) ] ;
}
rule FT2_Library
{
# FT2_Library <libname> : <sources>
# Builds objects from sources and adds the objects to the list of objects
# to be linked into the library.
# <libname> The name of the library.
# <sources> The sources.
local library = lib$(1).so ;
local sources = $(2) ;
SetupIncludes ;
SetupObjectsDir ;
MakeLocateObjects $(sources) ;
Objects $(sources) ;
LIBRARY_OBJECTS on $(library) += [ FGristFiles $(sources:S=$(SUFOBJ)) ] ;
}
rule FT2_LinkLibrary
{
# FT2_LinkLibrary <libname>
# Links the library from the objects build with FT2_LIBRARY before.
local library = lib$(1).so ;
local objects = [ on $(library) return $(LIBRARY_OBJECTS) ] ;
ObjectReferences $(objects) ;
objects = [ FGristFiles $(objects) ] ;
SharedLibraryFromObjects $(1) : $(objects) ;
}
#-------------------------------------------------------------------------------
# Packages for OBOS alpha/beta testers
#-------------------------------------------------------------------------------
rule Copy
{
Depends $(<) : $(>) ;
SEARCH on $(>) = $(SEARCH_SOURCE) ;
}
actions Copy
{
cp -dp "$(>)" "$(<)" ;
if [ -f "$(>)" ] ; then copyattr "$(>)" "$(<)" ; fi ;
}
rule Packages
{
local packagenames = $(1) ;
local packagefiles = $(2) ;
local path = $(3) ;
for name in $(packagenames) {
Package $(name) : $(packagefiles) : $(path) ;
}
}
rule Package
{
local packagename = $(1) ;
local packagefiles = $(2) ;
local path = $(3) ;
local packagezip = $(packagename:S=.zip:G=_packages) ;
local packagedir = [ FDirName $(OBOS_PACKAGE_DIR) $(packagename) ] ;
local installscript = install.sh ;
local packageinstallscript = $(installscript:G=_packages!$(packagename)) ;
local installzip = install.zip ;
local packageinstallzip = $(installzip:G=_packages!$(packagename)) ;
local packageobjectdir
= [ FDirName $(OBOS_PACKAGE_OBJECT_DIR) $(packagename) ] ;
local packagefiledir = [ FDirName $(packageobjectdir) $(path) ] ;
local packagefileinstallzip
= $(installzip:G=_package_objects!$(packagename)) ;
# add the files to the install.zip
local packagefilegrist = [ FGrist _package_files $(packagename) $(path) ] ;
for file in $(packagefiles) {
if $(3[0]) = "boot" {
local packagefile = $(file:G=$(packagefilegrist)) ;
MakeLocate $(packagefile) : $(packagefiledir) ;
Copy $(packagefile) : $(file) ;
Clean cleanPackages : $(packagefile) ;
PackageInstallZip $(packagefileinstallzip) : $(packagefile) ;
} else {
local packagefile = $(file:G=_packages!$(packagename)) ;
MakeLocate $(packagefile) : $(packagedir) ;
Copy $(packagefile) : [ FGristFiles $(file) ] ;
Clean cleanPackages : $(packagefile) ;
Depends $(packagezip) : $(packagefile) ;
}
}
# general setup for this packages -- only on first invocation
if ! $(_setup_$(packagename)) {
_setup_$(packagename) = true ;
NotFile $(packagename) ;
LocalDepends packages : $(packagename) ;
MakeLocate $(packagezip) : $(OBOS_PACKAGE_DIR) ;
MakeLocate $(packageinstallscript) : $(packagedir) ;
MakeLocate $(packageinstallzip) : $(packagedir) ;
MakeLocate $(packagefileinstallzip) : $(packageobjectdir) ;
PackageInstallScript $(packageinstallscript) : $(packagedir) ;
LinkInstallZip $(packageinstallzip) : $(packagefileinstallzip) ;
Depends $(packagename) : $(packagezip) ;
PackageZip $(packagezip) : $(packagedir)
: $(packageinstallscript) $(packageinstallzip) ;
}
}
rule PackageZip
{
local dir = $(2:G=dir) ;
Depends $(1) : $(dir) $(3) ;
Clean cleanPackages : $(1) ;
PackageZip1 $(1) : $(dir) ;
}
actions together PackageZip1 {
cd "$(OBOS_PACKAGE_DIR)" ;
zip -rq "$(1:BS)" "$(2:BS)" ;
}
rule PackageInstallScript
{
MakeLocate $(1) : $(2) ;
Clean cleanPackages : $(1) ;
PackageInstallScript1 $(1) : $(2:G=dir) ;
}
actions together PackageInstallScript1
{
echo '#!/bin/sh
base=`dirname "$0"`
cd "$base"
if [ -n "$TTY" ]
then
unzip -d / install.zip
else
response=`alert "Would you like to automatically overwrite existing files, or receive a prompt?" "Overwrite" "Prompt"`
if [ $response == "Overwrite" ]
then
unzip -od / install.zip
alert "Finished installing" "Thanks"
else
if [ -e /boot/beos/apps/Terminal ]
then
terminal=/boot/beos/apps/Terminal
else
terminal=`query Terminal | head -1`
fi
$terminal -t "installer" /bin/sh "$0"
fi
fi' > "$(1)" ;
chmod 755 "$(1)" ;
}
rule PackageInstallZip
{
Depends $(1) : $(2) ;
Clean cleanPackages : $(1) ;
}
actions together PackageInstallZip
{
cd "$(1:P)" ;
zip -rqy "$(1:BS)" boot ;
}
rule LinkInstallZip
{
Depends $(1) : $(2) ;
Clean cleanPackages : $(1) ;
}
actions together LinkInstallZip
{
ln -sf "`pwd`/$(2)" "$(1)" ;
}
rule SubIncludeGPL
{
# SubInclude rule that can be used to conditionally include GPL licensed add-ons
if $(INCLUDE_GPL_ADDONS) = 1 {
SubInclude $(1) ;
}
}