SubDir HAIKU_TOP src tools gensyscalls ;

SubDirHdrs [ FDirName $(SUBDIR) arch $(TARGET_ARCH) ] ;


# What want to do here is analyze the <syscalls.h> header and generate headers
# and sources containing information about the syscalls (like what parameters
# of what sizes and types they take, etc.) which will be used in other places
# (e.g. the kernel code or the strace tool).
#
# The strategy to achieve this is:
# * Preprocess the <syscalls.h> header, so that it is easier to parse.
# * Feed the preprocessed header to the gensyscallinfos tool. It will generate
#	a source file, gensyscalls_infos.cpp, which implements a function that
#	builds a table with all the syscall info information we need. The source
#	file needs specific infos about sizes of types, which aren't easily
#	available. That's why gensyscallinfos also generates a source file which
#	via the CreateAsmStructOffsetsHeader rule is turned into a header with
#	macro definitions for those type size. The header is included by
#	gensyscalls_infos.cpp.
# * gensyscalls.cpp and the generated gensyscalls_infos.cpp are compiled into
#	the gensyscalls tool.
# * gensyscalls has options to generate the various output files:
#	- <syscalls>syscalls.S.inc: Used to define the syscall functions in libroot.
#	- <syscalls>syscall_dispatcher.h: Big "switch" statement for the syscall
#	  dispatcher in the kernel.
#	- <syscalls>syscall_numbers.h: Macro definitions assigning indices to the
#	  syscalls.
#	- <syscalls>syscall_table.h: An array with syscall information in the
#	  kernel. Used for dispatching syscalls e.g. for x86.
#	- <syscalls>strace_syscalls.h: Syscall information needed by strace.


# preprocess the syscalls header

rule PreprocessSyscalls
{
	# PreprocessSyscalls <preprocessedHeader> : <header> ;

	Depends $(<) : $(>) ;

	local headers = [ on $(1) return $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ] ;
	local sysHeaders =
		$(TARGET_PRIVATE_SYSTEM_HEADERS)
		[ ArchHeaders $(TARGET_ARCH) ]
		[ on $(1) return $(SUBDIRSYSHDRS) $(SYSHDRS) ]
		$(HAIKU_HDRS) ;

	HDRS on $(<) = $(headers) ;
	SYSHDRS on $(<) = $(sysHeaders) ;

	HDRRULE on $(>) = HdrRule ;
	HDRSCAN on $(>) = $(HDRPATTERN) ;
	HDRSEARCH on $(>) = $(headers) $(sysHeaders) $(STDHDRS) ;
	HDRGRIST on $(>) = $(HDRGRIST) ;

	DEFINES on $(<) += $(HAIKU_DEFINES) GEN_SYSCALL_INFOS_PROCESSING ;

	CCFLAGS on $(<) += $(HAIKU_CCFLAGS) $(SUBDIRCCFLAGS) $(OPTIM) ;
	CCHDRS on $(<) = [ FIncludes $(headers) : $(HAIKU_LOCAL_INCLUDES_OPTION) ]
		$(HAIKU_INCLUDES_SEPARATOR)
		[ FSysIncludes $(sysHeaders) : $(HAIKU_SYSTEM_INCLUDES_OPTION) ] ;
	CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
}

actions PreprocessSyscalls
{
	$(HAIKU_C++) -xc++ -E "$(2)" $(CCFLAGS) $(CCDEFS) $(CCHDRS) -o "$(1)" ;
}

local syscallsHeader = [ FGristFiles syscalls.h ] ;
SEARCH on $(syscallsHeader) = [ FDirName $(HAIKU_TOP) headers private system ] ;

# Generate the preprocessed syscalls.h header. It will be parsed by
# gensyscallinfos (it contains marker #pragmas).
local syscallsHeaderPPParsable = [ FGristFiles syscalls.h.pp.parsable ] ;
MakeLocateArch $(syscallsHeaderPPParsable) ;
PreprocessSyscalls $(syscallsHeaderPPParsable) : $(syscallsHeader) ;


# build gensyscallinfos

BuildPlatformMain gensyscallinfos
	: gensyscallinfos.cpp
	: $(HOST_LIBSTDC++) $(HOST_LIBSUPC++)
;


# generate the syscall infos source file and the source for the header it
# includes

local syscallInfos = [ FGristFiles gensyscalls_infos.cpp ] ;
local syscallTypesSizesSource = [ FGristFiles syscall_types_sizes.h.cpp ] ;
local syscallTypesSizes = [ FGristFiles syscall_types_sizes.h ] ;
MakeLocateArch $(syscallInfos) $(syscallTypesSizesSource) $(syscallTypesSizes) ;

rule GenSyscallInfos
{
	Depends $(1) : gensyscallinfos $(2) ;
	GenSyscallInfos1 $(1) : gensyscallinfos $(2) ;
}

actions GenSyscallInfos1
{
	$(2[1]) $(2[2]) $(1)
}

GenSyscallInfos $(syscallInfos) $(syscallTypesSizesSource)
	: $(syscallsHeaderPPParsable) ;

TARGET_HDRS on $(syscallTypesSizes)
	= [ on $(syscallTypesSizes) return $(TARGET_HDRS) ]
		$(TARGET_PRIVATE_SYSTEM_HEADERS) ;
CreateAsmStructOffsetsHeader $(syscallTypesSizes) : $(syscallTypesSizesSource) ;

#Includes $(syscallInfos) : $(syscallTypesSizes) ;
	# explicitly tell jam about the inclusion of the generated header
Depends $(syscallInfos:S=$(SUFOBJ)) : $(syscallTypesSizes) ;
	# NOTE: Jam messes up the "Includes" declaration, so we have to declare
	# the dependency more directly.


# build gensyscalls

BuildPlatformMain gensyscalls : gensyscalls.cpp $(syscallInfos) ;
LinkAgainst gensyscalls : $(HOST_LIBSTDC++) $(HOST_LIBSUPC++) ;


# generate the output files

# place them where they are needed
local dir = $(HAIKU_COMMON_DEBUG_OBJECT_DIR) ;
MakeLocate <syscalls>syscalls.S.inc : [ FDirName $(dir) system libroot os ] ;
MakeLocate <syscalls>syscall_dispatcher.h : [ FDirName $(dir) system kernel ] ;
MakeLocate <syscalls>syscall_numbers.h : [ FDirName $(dir) system kernel ] ;
MakeLocate <syscalls>syscall_table.h : [ FDirName $(dir) system kernel ] ;
MakeLocate <syscalls>strace_syscalls.h : [ FDirName $(dir) bin debug strace ] ;

rule GenSyscallsFile file : option
{
	GENSYSCALLS_FILE_OPTION on $(file) = $(option) ;
	Depends $(file) : gensyscalls ;
	GenSyscallsFile1 $(file) : gensyscalls ;
}

actions GenSyscallsFile1
{
	$(2[1]) $(GENSYSCALLS_FILE_OPTION) $(1)
}

GenSyscallsFile <syscalls>syscalls.S.inc : -c ;
GenSyscallsFile <syscalls>syscall_dispatcher.h : -d ;
GenSyscallsFile <syscalls>syscall_numbers.h : -n ;
GenSyscallsFile <syscalls>syscall_table.h : -t ;
GenSyscallsFile <syscalls>strace_syscalls.h : -s ;
