From 97cc7e6be8a00c49c1f45fb8e613015eb71636f1 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sun, 15 Oct 2000 18:59:20 +0000 Subject: [PATCH] *** empty log message *** --- ppremake/Depends.pp | 28 +- ppremake/Global.stopgap.pp | 213 ++----------- ppremake/Makefile.am | 10 +- ppremake/System.pp | 11 +- ppremake/Template.stopgap.pp | 78 +++-- ppremake/configure.in | 2 +- ppremake/ppCommandFile.cxx | 341 ++++++++++++++++++--- ppremake/ppCommandFile.h | 13 +- ppremake/ppDirectoryTree.cxx | 24 +- ppremake/ppDirectoryTree.h | 3 +- ppremake/ppMain.cxx | 103 ++++++- ppremake/ppMain.h | 2 + ppremake/ppNamedScopes.cxx | 49 +++ ppremake/ppNamedScopes.h | 1 + ppremake/ppScope.cxx | 568 ++++++++++++++++++++++++++++------- ppremake/ppScope.h | 29 +- ppremake/ppSubroutine.cxx | 46 +++ ppremake/ppSubroutine.h | 5 + ppremake/ppremake.h | 2 + 19 files changed, 1089 insertions(+), 439 deletions(-) diff --git a/ppremake/Depends.pp b/ppremake/Depends.pp index 83db3d5396..879ac908db 100644 --- a/ppremake/Depends.pp +++ b/ppremake/Depends.pp @@ -6,19 +6,33 @@ // determining build order. // -#if $[eq $[DIR_TYPE], src] - +#if $[or $[eq $[DIR_TYPE], src], $[eq $[DIR_TYPE], metalib]] #if $[eq $[DEPENDS],] - #map local_libs TARGET(*/lib_target */noinst_lib_target) - // Allow the user to define additional DEPENDS targets in each // Sources.pp. #define DEPENDS #set DEPENDS $[EXTRA_DEPENDS] - #forscopes lib_target bin_target noinst_bin_target - #set DEPENDS $[DEPENDS] $[local_libs $[DIRNAME],$[LOCAL_LIBS]] $[LOCAL_INCS] - #end lib_target bin_target noinst_bin_target + #forscopes metalib_target static_lib_target lib_target noinst_lib_target bin_target noinst_bin_target + // We can optimize quite a bit by evaluating now several of the key + // deferred variables defined in Globals.pp. This way they won't need + // to get repeatedly reevaluated as each directory examines each + // other. + #define build_directory $[build_directory] + #define build_target $[build_target] + #define active_local_libs $[active_local_libs] + #define active_component_libs $[active_component_libs] + #define active_libs $[active_libs] + #define get_sources $[get_sources] + + // Report a warning for nonexisting dependencies. + #define nonexisting $[unmapped all_libs,$[LOCAL_LIBS]] + #if $[ne $[nonexisting],] +Warning: Lib(s) $[nonexisting], referenced in $[DIRNAME]/$[TARGET], not found. + #endif + + #set DEPENDS $[DEPENDS] $[all_libs $[DIRNAME],$[LOCAL_LIBS] $[COMPONENT_LIBS]] $[LOCAL_INCS] + #end metalib_target static_lib_target lib_target noinst_lib_target bin_target noinst_bin_target #set DEPENDS $[sort $[DEPENDS]] #endif diff --git a/ppremake/Global.stopgap.pp b/ppremake/Global.stopgap.pp index a0f9f03aee..8619a65fb9 100644 --- a/ppremake/Global.stopgap.pp +++ b/ppremake/Global.stopgap.pp @@ -6,196 +6,36 @@ // Template.stopgap.pp. // -// Define some various compile flags, derived from the variables set -// in Config.pp. -#if $[HAVE_PYTHON] - // We want to let the PYTHON_INCLUDE directory include wildcard characters. - #define python_ipath $[patsubst %,-I%,$[isdir $[PYTHON_IPATH]]] - #define python_lpath $[patsubst %,-L%,$[isdir $[PYTHON_LPATH]]] -#endif - -#if $[HAVE_NSPR] - // We want to let the NSPR directories include wildcard characters. - #define nspr_ipath $[patsubst %,-I%,$[isdir $[NSPR_IPATH]]] - #define nspr_lpath $[patsubst %,-L%,$[isdir $[NSPR_LPATH]]] - #define nspr_libs $[NSPR_LIBS] -#endif - -#if $[HAVE_ZLIB] - #define zlib_ipath $[ZLIB_IPATH:%=-I%] - #define zlib_lpath $[ZLIB_LPATH:%=-L%] - #define zlib_libs $[ZLIB_LIBS] -#endif - -#if $[HAVE_SOXST] - #define soxst_ipath $[SOXST_IPATH:%=-I%] - #define soxst_lpath $[SOXST_LPATH:%=-L%] - #define soxst_libs $[SOXST_LIBS] -#endif - -#if $[HAVE_GL] - #define gl_ipath $[GL_IPATH:%=-I%] - #define gl_lpath $[GL_LPATH:%=-L%] - #define gl_libs $[GL_LIBS] -#endif - -#if $[HAVE_DX] - #define dx_ipath $[DX_IPATH:%=-I%] - #define dx_lpath $[DX_LPATH:%=-L%] - #define dx_libs $[DX_LIBS] -#endif - -#if $[HAVE_MIKMOD] - #define mikmod_ipath $[MIKMOD_IPATH:%=-I%] - #define mikmod_cflags $[MIKMOD_CFLAGS] - #define mikmod_lpath $[MIKMOD_LPATH:%=-L%] - #define mikmod_libs $[MIKMOD_LIBS] -#endif - -#if $[HAVE_GTKMM] - #define gtkmm_ipath $[GTKMM_IPATH:%=-I%] - #define gtkmm_cflags $[GTKMM_CFLAGS] - #define gtkmm_lpath $[GTKMM_LPATH:%=-L%] - #define gtkmm_libs $[GTKMM_LIBS] -#endif - -#if $[and $[HAVE_MAYA],$[MAYA_LOCATION]] - #define maya_ipath -I$[MAYA_LOCATION]/include - #define maya_lpath -L$[MAYA_LOCATION]/lib - #define maya_ld $[MAYA_LOCATION]/bin/mayald -#endif - -#if $[HAVE_NET] - #define net_ipath $[NET_IPATH:%=-I%] - #define net_lpath $[NET_LPATH:%=-L%] - #define net_libs $[NET_LIBS] -#endif - -#if $[HAVE_AUDIO] - #define audio_ipath $[AUDIO_IPATH:%=-I%] - #define audio_lpath $[AUDIO_LPATH:%=-L%] - #define audio_libs $[AUDIO_LIBS] -#endif - - -// This variable, when evaluated in the scope of a particular directory, -// will indicate true (i.e. nonempty) when the directory is truly built, -// or false (empty) when the directory is not to be built. -#defer build_directory \ - $[and \ - $[or $[not $[DIRECTORY_IF_GL]],$[HAVE_GL]], \ - $[or $[not $[DIRECTORY_IF_DX]],$[HAVE_DX]], \ - $[or $[not $[DIRECTORY_IF_GLX]],$[HAVE_GLX]], \ - $[or $[not $[DIRECTORY_IF_GLUT]],$[HAVE_GLUT]], \ - $[or $[not $[DIRECTORY_IF_WGL]],$[HAVE_WGL]], \ - $[or $[not $[DIRECTORY_IF_RIB]],$[HAVE_RIB]], \ - $[or $[not $[DIRECTORY_IF_PS2]],$[HAVE_PS2]], \ - $[or $[not $[DIRECTORY_IF_SGIGL]],$[HAVE_SGIGL]], \ - $[or $[not $[DIRECTORY_IF_VRPN]],$[HAVE_VRPN]], \ - $[or $[not $[DIRECTORY_IF_NET]],$[HAVE_NET]], \ - $[or $[not $[DIRECTORY_IF_AUDIO]],$[HAVE_AUDIO]], \ - $[or $[not $[DIRECTORY_IF_GTKMM]],$[HAVE_GTKMM]], \ - $[or $[not $[DIRECTORY_IF_MAYA]],$[HAVE_MAYA]], \ - 1 ] - -// This variable is true if we are building on some flavor of Unix. -#define unix_platform $[ne $[PLATFORM],Win32] - -// This variable is true if we are building on some flavor of Windows. -#define windows_platform $[eq $[PLATFORM],Win32] - - -// This subroutine will set up the sources variable to reflect the -// complete set of sources for this target, and also set the -// alt_cflags, alt_libs, etc. as appropriate according to how the -// various USE_* flags are set for the current target. +// This subroutine fills sources, alt_cflags, alt_ipath, alt_lpath, +// alt_libs, and alt_ld as appropriate for the current target. +#define sources +#define alt_cflags +#define alt_ipath +#define alt_lpath +#define alt_libs +#define alt_ld #defsub get_sources - #define sources $[SOURCES] - #if $[ne $[HAVE_ZLIB],] - #set sources $[sources] $[IF_ZLIB_SOURCES] - #endif - #if $[ne $[HAVE_PYTHON],] - #set sources $[sources] $[IF_PYTHON_SOURCES] - #endif - - #define alt_cflags $[nspr_cflags] $[mikmod_cflags] $[python_cflags] - #define alt_ipath $[nspr_ipath] $[mikmod_ipath] $[python_ipath] - #define alt_lpath $[nspr_lpath] $[mikmod_lpath] $[python_lpath] - #define alt_libs $[nspr_libs] $[mikmod_libs] - #define alt_ld - - // If any of a metalib's constituent libraries require interrogate, - // then so does the metalib itself. To look this up, we need this map - // variable. - #map components TARGET(*/lib_target */noinst_lib_target) - - #if $[ne $[USE_ZLIB] $[components $[USE_ZLIB],$[COMPONENT_LIBS]],] - #set alt_cflags $[alt_cflags] $[zlib_cflags] - #set alt_ipath $[alt_ipath] $[zlib_ipath] - #set alt_lpath $[alt_lpath] $[zlib_lpath] - #set alt_libs $[alt_libs] $[zlib_libs] - #endif - #if $[ne $[USE_GL] $[components $[USE_GL],$[COMPONENT_LIBS]],] - #set alt_cflags $[alt_cflags] $[gl_cflags] - #set alt_ipath $[alt_ipath] $[gl_ipath] - #set alt_lpath $[alt_lpath] $[gl_lpath] - #set alt_libs $[alt_libs] $[gl_libs] - #endif - #if $[ne $[USE_DX] $[components $[USE_DX],$[COMPONENT_LIBS]],] - #set alt_cflags $[alt_cflags] $[dx_cflags] - #set alt_ipath $[alt_ipath] $[dx_ipath] - #set alt_lpath $[alt_lpath] $[dx_lpath] - #set alt_libs $[alt_libs] $[dx_libs] - #endif - #if $[ne $[USE_SOXST] $[components $[USE_SOXST],$[COMPONENT_LIBS]],] - #set alt_cflags $[alt_cflags] $[soxst_cflags] - #set alt_ipath $[alt_ipath] $[soxst_ipath] - #set alt_lpath $[alt_lpath] $[soxst_lpath] - #set alt_libs $[alt_libs] $[soxst_libs] - #endif - #if $[ne $[USE_NET] $[components $[USE_NET],$[COMPONENT_LIBS]],] - #set alt_cflags $[alt_cflags] $[net_cflags] - #set alt_ipath $[alt_ipath] $[net_ipath] - #set alt_lpath $[alt_lpath] $[net_lpath] - #set alt_libs $[alt_libs] $[net_libs] - #endif - #if $[ne $[USE_AUDIO] $[components $[USE_AUDIO],$[COMPONENT_LIBS]],] - #set alt_cflags $[alt_cflags] $[audio_cflags] - #set alt_ipath $[alt_ipath] $[audio_ipath] - #set alt_lpath $[alt_lpath] $[audio_lpath] - #set alt_libs $[alt_libs] $[audio_libs] - #endif - #if $[ne $[USE_GTKMM] $[components $[USE_GTKMM],$[COMPONENT_LIBS]],] - #set alt_cflags $[alt_cflags] $[gtkmm_cflags] - #set alt_ipath $[alt_ipath] $[gtkmm_ipath] - #set alt_lpath $[alt_lpath] $[gtkmm_lpath] - #set alt_libs $[alt_libs] $[gtkmm_libs] - #endif - #if $[ne $[USE_MAYA] $[components $[USE_MAYA],$[COMPONENT_LIBS]],] - #set alt_cflags $[alt_cflags] $[maya_cflags] - #set alt_ipath $[alt_ipath] $[maya_ipath] - #set alt_lpath $[alt_lpath] $[maya_lpath] - #set alt_libs $[alt_libs] $[maya_libs] - #set alt_ld $[maya_ld] - #endif - #if $[unix_platform] - #set alt_libs $[alt_libs] $[UNIX_SYS_LIBS] $[components $[UNIX_SYS_LIBS],$[COMPONENT_LIBS]] - #endif + #set sources $[get_sources] + #set alt_cflags $[get_cflags] + #set alt_ipath $[get_ipath] + #set alt_lpath $[get_lpath] + #set alt_libs $[get_libs] + #set alt_ld $[get_ld] #end get_sources // This subroutine will set when_defer, when_no_defer, and when_either -// correctly to the set of libs we should link with for current +// correctly to the set of libs we should link with for the current // target. +#define when_defer +#define when_no_defer +#define when_either #defsub get_libs // For the WHEN_DEFER case, we need to know the complete set of // metalibs that encapsulates each of our LOCAL_LIBS. In the case // where a particular library is not part of a metalib, we include the // library itself. - // These map variables are handy to determine that. - #map module COMPONENT_LIBS(*/metalib_target) - #map all_libs TARGET(*/static_lib_target */lib_target */noinst_lib_target */metalib_target) - #define when_defer + #set when_defer #foreach lib $[LOCAL_LIBS] // Only consider libraries that we're actually building. #if $[all_libs $[build_directory],$[lib]] @@ -211,7 +51,7 @@ // Also filter out the libraries we don't want from when_no_defer, although // we don't need to translate these to metalibs. - #define when_no_defer + #set when_no_defer #foreach lib $[COMPONENT_LIBS] $[LOCAL_LIBS] #if $[all_libs $[build_directory],$[lib]] #set when_no_defer $[when_no_defer] $[lib] @@ -222,7 +62,7 @@ // Finally, get the set of libraries that we want in either case. At // the moment, this is just the set of libraries in OTHER_LIBS that's // not flagged with either a :c or a :m. - #define when_either $[filter-out %:m %:c,$[OTHER_LIBS]] + #set when_either $[filter-out %:m %:c,$[OTHER_LIBS]] #end get_libs @@ -230,9 +70,6 @@ // to a list of the form libname.so or libname.a, according to whether the // named libraries are static or dynamic. #defsub convert_depend_libs - #map static_libs TARGET(*/static_lib_target) - #map dynamic_libs TARGET(*/lib_target */metalib_target) - #map all_libs TARGET(*/static_lib_target */lib_target */metalib_target) #define new_depend_libs #foreach lib $[depend_libs] // Make sure the library is something we're actually building. @@ -258,10 +95,9 @@ // and (b) indirectly on all of the metalibs that every other library // dependency is part of. If a target is not part of a metalib, it is // the same as case (b) above. +#define depend_libs #defsub get_depend_libs - #map module COMPONENT_LIBS(*/metalib_target) - - #define depend_libs + #set depend_libs #forscopes lib_target noinst_lib_target #define metalib $[module $[TARGET],$[TARGET]] #if $[ne $[metalib],] @@ -314,9 +150,6 @@ // Now correct all the libraries listed in depend_libs to refer to a // real library name. - #map static_libs TARGET(*/static_lib_target) - #map dynamic_libs TARGET(*/lib_target */metalib_target) - #map all_libs TARGET(*/static_lib_target */lib_target */metalib_target) #define new_depend_libs #foreach lib $[sort $[depend_libs]] // Make sure the library is something we're actually building. diff --git a/ppremake/Makefile.am b/ppremake/Makefile.am index 435f36d3a6..538639f6da 100644 --- a/ppremake/Makefile.am +++ b/ppremake/Makefile.am @@ -12,9 +12,11 @@ ppremake_SOURCES = \ tokenize.h data_DATA = \ - System.pp Depends.pp Template.autoconf.pp \ - Global.stopgap.pp Template.stopgap.pp + System.pp Depends.pp Global.pp Template.autoconf.pp \ + Global.stopgap.pp Template.stopgap.pp \ + Global.unix.pp Template.unix.pp EXTRA_DIST =\ - System.pp Depends.pp Template.autoconf.pp \ - Global.stopgap.pp Template.stopgap.pp + System.pp Depends.pp Global.pp Template.autoconf.pp \ + Global.stopgap.pp Template.stopgap.pp \ + Global.unix.pp Template.unix.pp diff --git a/ppremake/System.pp b/ppremake/System.pp index edc33fa049..74b7c369f5 100644 --- a/ppremake/System.pp +++ b/ppremake/System.pp @@ -21,14 +21,13 @@ #endif #if $[eq $[GLOBAL_FILE],] - #define GLOBAL_FILE $[PPREMAKE_DIR]/Global.$[BUILD_TYPE].pp + #define GLOBAL_FILE $[PPREMAKE_DIR]/Global.pp +#endif + +#if $[eq $[GLOBAL_TYPE_FILE],] + #define GLOBAL_TYPE_FILE $[PPREMAKE_DIR]/Global.$[BUILD_TYPE].pp #endif #if $[eq $[TEMPLATE_FILE],] #define TEMPLATE_FILE $[PPREMAKE_DIR]/Template.$[BUILD_TYPE].pp #endif - -// Include the global definitions for the template type, if the file -// is there. -#sinclude $[GLOBAL_FILE] - diff --git a/ppremake/Template.stopgap.pp b/ppremake/Template.stopgap.pp index 2cf41ba727..bcb6215cc4 100644 --- a/ppremake/Template.stopgap.pp +++ b/ppremake/Template.stopgap.pp @@ -16,11 +16,6 @@ #define submakes $[TARGET(static_lib_target):%=%.a] $[TARGET(lib_target noinst_lib_target):%=%.so] $[TARGET(sed_bin_target bin_target noinst_bin_target test_bin_target)] #define install $[TARGET(static_lib_target):%=%.a] $[TARGET(lib_target noinst_lib_target):%=%.so] $[TARGET(sed_bin_target bin_target noinst_bin_target)] - -// This map variable lets us identify which metalib, if any, is -// including each library built here. -#map module COMPONENT_LIBS(*/metalib_target) - // Now iterate through the libraries we're building and see which ones // actually *are* being included in a metalib. For each one that is, // we install the appropriate deferred file. @@ -40,7 +35,7 @@ #define install_bin $[sort $[TARGET(bin_target)] $[INSTALL_BIN]] #define install_scripts $[sort $[INSTALL_SCRIPTS(static_lib_target lib_target bin_target)] $[TARGET(sed_bin_target)] $[INSTALL_SCRIPTS]] #define install_headers $[sort $[INSTALL_HEADERS(static_lib_target lib_target bin_target)] $[INSTALL_HEADERS]] -#define install_data $[sort $[INSTALL_DATA(static_lib_target lib_target sed_bin_target bin_target)] $[INSTALL_DATA]] +#define install_data $[sort $[INSTALL_DATA(static_lib_target lib_target sed_bin_target bin_target)] $[INSTALL_DATA]] $[sort $[INSTALL_CONFIG(static_lib_target lib_target sed_bin_target bin_target)] $[INSTALL_CONFIG]] // Collect the set of interrogate database files we'll install, // possibly one for each library we build. @@ -71,7 +66,7 @@ INSTALL = $[install] MAKEDIR = . #### The action is here. -include $(DTOOL)/inc/Makefile.meta.rules +include $(DTOOL)/include/Makefile.meta.rules #### Sub-make build order dependencies: # foo: bar @@ -123,14 +118,14 @@ IGATEDB =$[install_igatedb] #if $[ne $[INSTALL_PARSER_INC],] PARSER_INC = $[INSTALL_PARSER_INC] SRC_PARSER_INC = $(addprefix $(PKGROOT)/,$(PARSER_INC)) -INST_PARSER_INC = $(addprefix inc/parser-inc/,$(PARSER_INC)) +INST_PARSER_INC = $(addprefix include/parser-inc/,$(PARSER_INC)) OTHER = $(INST_PARSER_INC) #else # OTHER = #endif #### Where the action happens. -include $(DTOOL)/inc/Makefile.install.rules +include $(DTOOL)/include/Makefile.install.rules #### Install actions for OTHER files (source must be in $(PKGROOT)): # [ installed file ] : $(PKGROOT)/[ source file ] # Files must have same name @@ -140,7 +135,7 @@ include $(DTOOL)/inc/Makefile.install.rules # $(MKINSTALL) # Also makes directory if needed #if $[ne $[INSTALL_PARSER_INC],] -$(INST_PARSER_INC) : inc/parser-inc/% : $(PKGROOT)/% +$(INST_PARSER_INC) : include/parser-inc/% : $(PKGROOT)/% $(MKINSTALL) #endif @@ -226,11 +221,11 @@ C++FLAGS = $[building_var:%=-D%] $[alt_cflags] $[C++FLAGS] #### Interrogate info IGATESCAN = $[igatescan] -IGATEFLAGS = $[alt_ipath] +IGATEFLAGS = $[alt_ipath:%=-I%] # IGATEFILE = # Specify only if you want a specific name #### Additional search directories for C/C++ header files: -IPATH = $[alt_ipath] +IPATH = $[alt_ipath:%=-I%] #### Location to put .o files: # ODIR = @@ -246,7 +241,7 @@ LIBS = $[when_either:%=-l%] SYSLIBS = $[patsubst %.lib,%.lib,%,-l%,$[unique $[alt_libs]]] #### Additional search directories for lib: -LPATH = $[alt_lpath] +LPATH = $[alt_lpath:%=-L%] #### Other linker flags. #if $[ne $[alt_ld],] @@ -255,16 +250,16 @@ LD = $[alt_ld] # LDFLAGS = #### Pull in standard .o make variables -include $(DTOOL)/inc/Makefile.o.vars +include $(DTOOL)/include/Makefile.o.vars #### The .o action is here. -include $(DTOOL)/inc/Makefile.o.rules +include $(DTOOL)/include/Makefile.o.rules #### Pull in standard binary make variables. -include $(DTOOL)/inc/Makefile.bin.vars +include $(DTOOL)/include/Makefile.bin.vars #### The .so action is here. -include $(DTOOL)/inc/Makefile.so.rules +include $(DTOOL)/include/Makefile.so.rules #end Makefile.$[TARGET].so #end lib_target noinst_lib_target @@ -314,7 +309,7 @@ C++FLAGS = $[building_var:%=-D%] $[alt_cflags] $[C++FLAGS] # PTREPOSITORY = # Specify only if you want a specific name #### Additional search directories for C/C++ header files: -IPATH = $[alt_ipath] +IPATH = $[alt_ipath:%=-I%] #### Location to put .o files: # ODIR = @@ -332,22 +327,22 @@ LIBS = $[when_either:%=-l%] SYSLIBS = $[patsubst %.lib,%.lib,%,-l%,$[unique $[alt_libs]]] #### Additional search directories for lib: -LPATH = $[alt_lpath] +LPATH = $[alt_lpath:%=-L%] #### Archiver flags # ARFLAGS = #### Pull in standard .o make variables -include $(DTOOL)/inc/Makefile.o.vars +include $(DTOOL)/include/Makefile.o.vars #### The .o action is here. -include $(DTOOL)/inc/Makefile.o.rules +include $(DTOOL)/include/Makefile.o.rules #### Pull in standard binary make variables. -include $(DTOOL)/inc/Makefile.bin.vars +include $(DTOOL)/include/Makefile.bin.vars #### The .a action is here. -include $(DTOOL)/inc/Makefile.a.rules +include $(DTOOL)/include/Makefile.a.rules #end Makefile.$[TARGET].a #end static_lib_target @@ -395,7 +390,7 @@ C++FILES = $[filter %.cxx,$[sources]] C++FLAGS = $[building_var:%=-D%] $[alt_cflags] $[C++FLAGS] #### Additional search directories for C/C++ header files: -IPATH = $[alt_ipath] +IPATH = $[alt_ipath:%=-I%] #### Location to put .o files: # ODIR = @@ -411,7 +406,7 @@ LIBS = $[when_either:%=-l%] SYSLIBS = $[patsubst %.lib,%.lib,%,-l%,$[unique $[alt_libs]]] #### Additional search directories for lib: -LPATH = $[alt_lpath] +LPATH = $[alt_lpath:%=-L%] #### Other linker flags. #if $[ne $[alt_ld],] @@ -420,16 +415,16 @@ LD = $[alt_ld] # LDFLAGS = #### Pull in standard .o make variables -include $(DTOOL)/inc/Makefile.o.vars +include $(DTOOL)/include/Makefile.o.vars #### The .o action is here. -include $(DTOOL)/inc/Makefile.o.rules +include $(DTOOL)/include/Makefile.o.rules #### Pull in standard binary make variables. -include $(DTOOL)/inc/Makefile.bin.vars +include $(DTOOL)/include/Makefile.bin.vars #### The bin action is here. -include $(DTOOL)/inc/Makefile.bin.rules +include $(DTOOL)/include/Makefile.bin.rules #end Makefile.$[TARGET] #end bin_target noinst_bin_target test_bin_target @@ -465,17 +460,13 @@ cleanall : #define submakes $[TARGET(metalib_target):%=%.so] -// This map variable lets us identify which metalib, if any, is -// including each library built here. -#map module COMPONENT_LIBS(*/metalib_target) - // Get the full set of libraries we depend on. #call get_depend_libs // Also get the targets we'll be installing. #define install_libs $[TARGET(metalib_target):%=lib%.so] #define install_headers $[INSTALL_HEADERS(metalib_target)] -#define install_data $[INSTALL_DATA(metalib_target)] +#define install_data $[INSTALL_DATA(metalib_target)] $[INSTALL_CONFIG(metalib_target)] #output Makefile @@ -495,7 +486,7 @@ INSTALL = $[submakes] MAKEDIR = . #### The action is here. -include $(DTOOL)/inc/Makefile.meta.rules +include $(DTOOL)/include/Makefile.meta.rules #### Sub-make build order dependencies: # foo: bar @@ -544,7 +535,7 @@ INCLUDE = $[install_headers] # OTHER = #### Where the action happens. -include $(DTOOL)/inc/Makefile.install.rules +include $(DTOOL)/include/Makefile.install.rules #### Install actions for OTHER files (source must be in $(PKGROOT)): # [ installed file ] : $(PKGROOT)/[ source file ] # Files must have same name @@ -576,7 +567,6 @@ endif #call get_libs #if $[HAVE_PYTHON] - #map components TARGET(*/lib_target */noinst_lib_target) #if $[ne $[components $[IGATESCAN],$[COMPONENT_LIBS]],] #define igatemscan $[TARGET] #endif @@ -627,7 +617,7 @@ IGATEMSCAN = $[igatemscan] DEFERRED_FILES = $[TARGET] #### Additional search directories for C/C++ header files: -IPATH = $[alt_ipath] +IPATH = $[alt_ipath:%=-I%] #### Location to put .o files: # ODIR = @@ -643,7 +633,7 @@ LIBS = $[when_either:%=-l%] SYSLIBS = $[patsubst %.lib,%.lib,%,-l%,$[unique $[alt_libs]]] #### Additional search directories for lib: -LPATH = $[alt_lpath] +LPATH = $[alt_lpath:%=-L%] #### Other linker flags. #if $[ne $[alt_ld],] @@ -652,16 +642,16 @@ LD = $[alt_ld] # LDFLAGS = #### Pull in standard .o make variables -include $(DTOOL)/inc/Makefile.o.vars +include $(DTOOL)/include/Makefile.o.vars #### The .o action is here. -include $(DTOOL)/inc/Makefile.o.rules +include $(DTOOL)/include/Makefile.o.rules #### Pull in standard binary make variables. -include $(DTOOL)/inc/Makefile.bin.vars +include $(DTOOL)/include/Makefile.bin.vars #### The .so action is here. -include $(DTOOL)/inc/Makefile.so.rules +include $(DTOOL)/include/Makefile.so.rules #end Makefile.$[TARGET].so #end metalib_target @@ -694,7 +684,7 @@ include $(DTOOL)/inc/Makefile.so.rules CTPROJECT = $[PACKAGE] CTPROJROOT = $($[upcase $[PACKAGE]]) -include $(DTOOL)/inc/Makefile.project.vars +include $(DTOOL)/include/Makefile.project.vars // Iterate through all of our known source files. Each src and // metalib type file gets its corresponding Makefile.install listed diff --git a/ppremake/configure.in b/ppremake/configure.in index ea6345f917..c8e5b899d4 100644 --- a/ppremake/configure.in +++ b/ppremake/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(ppremake.cxx) -AM_INIT_AUTOMAKE(ppremake, 0.25a) +AM_INIT_AUTOMAKE(ppremake, 0.26) AM_CONFIG_HEADER(config.h) AC_PREFIX_DEFAULT(/usr/local/panda) diff --git a/ppremake/ppCommandFile.cxx b/ppremake/ppCommandFile.cxx index 8baa6e3201..b9401bf593 100644 --- a/ppremake/ppCommandFile.cxx +++ b/ppremake/ppCommandFile.cxx @@ -152,6 +152,18 @@ PPCommandFile:: delete _write_state; } +//////////////////////////////////////////////////////////////////// +// Function: PPCommandFile::set_output +// Access: Public +// Description: Changes the main output stream that will be written +// to when text appears outside of a #output .. #end +// block. This is cout by default. +//////////////////////////////////////////////////////////////////// +void PPCommandFile:: +set_output(ostream *out) { + _write_state->_out = out; +} + //////////////////////////////////////////////////////////////////// // Function: PPCommandFile::set_scope // Access: Public @@ -343,10 +355,19 @@ end_read() { cerr << "Unclosed foreach " << _block_nesting->_name << "\n"; break; + case BS_formap: + case BS_nested_formap: + cerr << "Unclosed formap " << _block_nesting->_name << "\n"; + break; + case BS_defsub: cerr << "Unclosed defsub " << _block_nesting->_name << "\n"; break; + case BS_defun: + cerr << "Unclosed defun " << _block_nesting->_name << "\n"; + break; + case BS_output: cerr << "Unclosed output " << _block_nesting->_name << "\n"; break; @@ -424,14 +445,23 @@ handle_command(const string &line) { } else if (_command == "foreach") { return handle_foreach_command(); + } else if (_command == "formap") { + return handle_formap_command(); + } else if (_command == "format") { return handle_format_command(); } else if (_command == "output") { return handle_output_command(); + } else if (_command == "print") { + return handle_print_command(); + } else if (_command == "defsub") { - return handle_defsub_command(); + return handle_defsub_command(true); + + } else if (_command == "defun") { + return handle_defsub_command(false); } else if (_command == "end") { return handle_end_command(); @@ -464,6 +494,9 @@ handle_command(const string &line) { } else if (_command == "map") { return handle_map_command(); + + } else if (_command == "addmap") { + return handle_addmap_command(); } cerr << "Invalid command: " << COMMAND_PREFIX << _command << "\n"; @@ -700,6 +733,7 @@ handle_foreach_command() { nest->_scope = _scope; nest->_next = _block_nesting; + // We insert in all but the first word in the words vector. nest->_words.insert(nest->_words.end(), words.begin() + 1, words.end()); _block_nesting = nest; @@ -712,6 +746,49 @@ handle_foreach_command() { return true; } +//////////////////////////////////////////////////////////////////// +// Function: PPCommandFile::handle_formap_command +// Access: Protected +// Description: Handles the #formap command: interpret all the lines +// between this command and the corresponding #end +// command once for each key in the map, and also within +// the corresponding scope of that particular key. +//////////////////////////////////////////////////////////////////// +bool PPCommandFile:: +handle_formap_command() { + // Get the parameters of the formap command. The first word is the + // name of the variable to substitute in (and which should appear on + // the matching #end command), and the second word is the name of + // the map variable. + vector words; + tokenize_whitespace(_scope->expand_string(_params), words); + + if (words.size() != 2) { + cerr << "#formap requires exactly two parameters.\n"; + return false; + } + + string variable_name = words.front(); + + BlockNesting *nest = new BlockNesting; + nest->_state = _in_for ? BS_nested_formap : BS_formap; + nest->_name = words[0]; + nest->_write_state = _write_state; + nest->_scope = _scope; + nest->_next = _block_nesting; + + nest->_words.push_back(words[1]); + + _block_nesting = nest; + + if (!_in_for) { + _in_for = true; + _saved_lines.clear(); + } + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: PPCommandFile::handle_format_command // Access: Protected @@ -802,35 +879,74 @@ handle_output_command() { } //////////////////////////////////////////////////////////////////// -// Function: PPCommandFile::handle_defsub_command +// Function: PPCommandFile::handle_print_command // Access: Protected -// Description: Handles the #defsub command: save all the lines -// between this command and the matching #end as a -// callable subroutine to be invoked by a later #call -// command. +// Description: Handles the #print command: immediately output the +// arguments to this line to standard error. //////////////////////////////////////////////////////////////////// bool PPCommandFile:: -handle_defsub_command() { - // The only parameter of #defsub is the name of the subroutine. - string subroutine_name = trim_blanks(_scope->expand_string(_params)); +handle_print_command() { + if (!_in_for) { + cerr << _scope->expand_string(_params) << "\n"; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PPCommandFile::handle_defsub_command +// Access: Protected +// Description: Handles the #defsub (or #defun) command: save all the +// lines between this command and the matching #end as a +// callable subroutine to be invoked by a later #call +// command. If is_defsub is false, it means this +// subroutine was actually defined via a #defun command, +// so it is to be invoked by a later variable reference, +// instead of by a #call command. +//////////////////////////////////////////////////////////////////// +bool PPCommandFile:: +handle_defsub_command(bool is_defsub) { + string command = (is_defsub) ? "#defsub" : "#defun"; + + // The first word of the parameter list is the subroutine name; the + // rest is the comma-separated list of formal parameter names. + + // Pull off the first word and the rest of the params. + size_t p = 0; + while (p < _params.length() && !isspace(_params[p])) { + p++; + } + string subroutine_name = trim_blanks(_params.substr(0, p)); if (subroutine_name.empty()) { - cerr << "#defsub requires at least one parameter.\n"; + cerr << command << " requires at least one parameter.\n"; return false; } + vector formals; + _scope->tokenize_params(_params.substr(p), formals, false); + + vector::const_iterator fi; + for (fi = formals.begin(); fi != formals.end(); ++fi) { + if (!is_valid_formal(*fi)) { + cerr << command << " " << subroutine_name + << ": invalid formal parameter name '" << (*fi) << "'\n"; + return false; + } + } + if (_in_for) { - cerr << "#defsub may not appear within a #forscopes or #foreach block,\n" - << "or within another #defsub block.\n"; + cerr << command << " may not appear within another block scoping command like\n" + << "#forscopes, #foreach, #formap, #defsub, or #defun.\n"; return false; } BlockNesting *nest = new BlockNesting; - nest->_state = BS_defsub; + nest->_state = is_defsub ? BS_defsub : BS_defun; nest->_name = subroutine_name; nest->_write_state = _write_state; nest->_scope = _scope; nest->_next = _block_nesting; + nest->_words.swap(formals); _block_nesting = nest; @@ -884,10 +1000,19 @@ handle_end_command() { return false; } - } else if (nest->_state == BS_defsub) { + } else if (nest->_state == BS_formap) { + // Now replay all of the saved lines. + _in_for = false; + assert(nest->_words.size() == 1); + if (!replay_formap(nest->_name, nest->_words[0])) { + return false; + } + + } else if (nest->_state == BS_defsub || nest->_state == BS_defun) { // Save all of the saved lines as a named subroutine. _in_for = false; PPSubroutine *sub = new PPSubroutine; + sub->_formals.swap(nest->_words); sub->_lines.swap(_saved_lines); // Remove the #end command. This will fail if someone makes an @@ -895,7 +1020,11 @@ handle_end_command() { assert(!sub->_lines.empty()); sub->_lines.pop_back(); - PPSubroutine::define_sub(nest->_name, sub); + if (nest->_state == BS_defsub) { + PPSubroutine::define_sub(nest->_name, sub); + } else { + PPSubroutine::define_func(nest->_name, sub); + } } else if (nest->_state == BS_output) { if (!_in_for) { @@ -976,10 +1105,21 @@ handle_sinclude_command() { //////////////////////////////////////////////////////////////////// bool PPCommandFile:: handle_call_command() { - string subroutine_name = trim_blanks(_scope->expand_string(_params)); + // The first word is the name of the subroutine; the rest is the + // comma-separated list of expressions to substitute in for the + // subroutine's formal parameters. + + // Pull off the first word and the rest of the params. + size_t p = 0; + while (p < _params.length() && !isspace(_params[p])) { + p++; + } + string subroutine_name = trim_blanks(_params.substr(0, p)); + string params = _params.substr(p); if (subroutine_name.empty()) { - cerr << "#call with no parameter.\n"; + cerr << "#call requires at least one parameter.\n"; + return false; } const PPSubroutine *sub = PPSubroutine::get_sub(subroutine_name); @@ -987,13 +1127,23 @@ handle_call_command() { cerr << "Attempt to call undefined subroutine " << subroutine_name << "\n"; } + PPScope *old_scope = _scope; + PPScope::push_scope(_scope); + PPScope nested_scope(_scope->get_named_scopes()); + _scope = &nested_scope; + nested_scope.define_formals(subroutine_name, sub->_formals, params); + vector::const_iterator li; for (li = sub->_lines.begin(); li != sub->_lines.end(); ++li) { if (!read_line(*li)) { + PPScope::pop_scope(); + _scope = old_scope; return false; } } + PPScope::pop_scope(); + _scope = old_scope; return true; } @@ -1005,8 +1155,10 @@ handle_call_command() { //////////////////////////////////////////////////////////////////// bool PPCommandFile:: handle_error_command() { - if (!_params.empty()) { - cerr << _params << "\n"; + string message = trim_blanks(_scope->expand_string(_params)); + + if (!message.empty()) { + cerr << message << "\n"; } return false; } @@ -1031,6 +1183,11 @@ handle_defer_command() { p++; } string varname = _params.substr(0, p); + + if (PPSubroutine::get_func(varname) != (const PPSubroutine *)NULL) { + cerr << "Warning: variable " << varname + << " shadowed by function definition.\n"; + } // Skip whitespace between the variable name and its definition. while (p < _params.length() && isspace(_params[p])) { @@ -1065,6 +1222,11 @@ handle_define_command() { p++; } string varname = _params.substr(0, p); + + if (PPSubroutine::get_func(varname) != (const PPSubroutine *)NULL) { + cerr << "Warning: variable " << varname + << " shadowed by function definition.\n"; + } // Skip whitespace between the variable name and its definition. while (p < _params.length() && isspace(_params[p])) { @@ -1099,6 +1261,11 @@ handle_set_command() { p++; } string varname = _params.substr(0, p); + + if (PPSubroutine::get_func(varname) != (const PPSubroutine *)NULL) { + cerr << "Warning: variable " << varname + << " shadowed by function definition.\n"; + } // Skip whitespace between the variable name and its definition. while (p < _params.length() && isspace(_params[p])) { @@ -1136,18 +1303,37 @@ handle_map_command() { while (p < _params.length() && isspace(_params[p])) { p++; } - string def = _params.substr(p); - - // We don't expand the variable's definition immediately; it will be - // expanded when the variable is referenced later. However, we - // should expand any simple self-reference immediately, to allow for - // recursive definitions. - def = _scope->expand_string(def); + string def = trim_blanks(_params.substr(p)); _scope->define_map_variable(varname, def); return true; } +//////////////////////////////////////////////////////////////////// +// Function: PPCommandFile::handle_addmap_command +// Access: Protected +// Description: Handles the #addmap command: add a new key/scope pair +// to an existing map variable. +//////////////////////////////////////////////////////////////////// +bool PPCommandFile:: +handle_addmap_command() { + // Pull off the first word and the rest of the params. + size_t p = 0; + while (p < _params.length() && !isspace(_params[p])) { + p++; + } + string varname = _params.substr(0, p); + + // Skip whitespace between the variable name and the key. + while (p < _params.length() && isspace(_params[p])) { + p++; + } + string key = trim_blanks(_scope->expand_string(_params.substr(p))); + + _scope->add_to_map_variable(varname, key, _scope); + return true; +} + //////////////////////////////////////////////////////////////////// // Function: PPCommandFile::include_file @@ -1208,23 +1394,24 @@ replay_forscopes(const string &name) { vector words; tokenize_whitespace(name, words); - // Now traverse the named scopes with these names. + // Now build up the list of scopes with these names. + PPNamedScopes::Scopes scopes; vector::const_iterator wi; for (wi = words.begin(); wi != words.end(); ++wi) { - PPNamedScopes::Scopes scopes; named_scopes->get_scopes(*wi, scopes); + } + PPNamedScopes::sort_by_dependency(scopes); - PPNamedScopes::Scopes::const_iterator si; - for (si = scopes.begin(); si != scopes.end(); ++si) { - PPScope::push_scope(_scope); - _scope = (*si); - - vector::const_iterator li; - for (li = lines.begin(); li != lines.end() && okflag; ++li) { - okflag = read_line(*li); - } - _scope = PPScope::pop_scope(); + PPNamedScopes::Scopes::const_iterator si; + for (si = scopes.begin(); si != scopes.end(); ++si) { + PPScope::push_scope(_scope); + _scope = (*si); + + vector::const_iterator li; + for (li = lines.begin(); li != lines.end() && okflag; ++li) { + okflag = read_line(*li); } + _scope = PPScope::pop_scope(); } return okflag; @@ -1261,6 +1448,51 @@ replay_foreach(const string &varname, const vector &words) { return okflag; } +//////////////////////////////////////////////////////////////////// +// Function: PPCommandFile::replay_formap +// Access: Protected +// Description: Replays all the lines that were saved during a +// previous #formap..#end block. +//////////////////////////////////////////////////////////////////// +bool PPCommandFile:: +replay_formap(const string &varname, const string &mapvar) { + bool okflag = true; + + vector lines; + lines.swap(_saved_lines); + + // Remove the #end command. This will fail if someone makes an #end + // command that spans multiple lines. Don't do that. + assert(!lines.empty()); + lines.pop_back(); + + // Now look up the map variable. + PPScope::MapVariableDefinition &def = _scope->find_map_variable(mapvar); + if (&def == &PPScope::_null_map_def) { + cerr << "Undefined map variable: #formap " << varname << " " + << mapvar << "\n"; + return false; + } + + // Now traverse through the map definition. + PPScope::MapVariableDefinition::const_iterator di; + for (di = def.begin(); di != def.end() && okflag; ++di) { + _scope->define_variable(varname, (*di).first); + + PPScope::push_scope(_scope); + _scope = (*di).second; + + vector::const_iterator li; + for (li = lines.begin(); li != lines.end() && okflag; ++li) { + okflag = read_line(*li); + } + + _scope = PPScope::pop_scope(); + } + + return okflag; +} + //////////////////////////////////////////////////////////////////// // Function: PPCommandFile::compare_output // Access: Protected @@ -1324,6 +1556,39 @@ failed_if() const { (_if_nesting->_state == IS_off || _if_nesting->_state == IS_done)); } +//////////////////////////////////////////////////////////////////// +// Function: PPCommandFile::is_valid_formal_parameter_name +// Access: Protected +// Description: Returns true if the indicated name is an acceptable +// name for a formal parameter. This means it includes +// no whitespace or crazy punctuation. Mainly this is +// to protect the user from making some stupid syntax +// mistake. +//////////////////////////////////////////////////////////////////// +bool PPCommandFile:: +is_valid_formal(const string &formal_parameter_name) const { + if (formal_parameter_name.empty()) { + return false; + } + + string::const_iterator si; + for (si = formal_parameter_name.begin(); + si != formal_parameter_name.end(); + ++si) { + switch (*si) { + case ' ': + case '\n': + case '\t': + case '$': + case '[': + case ']': + case ',': + return false; + } + } + + return true; +} //////////////////////////////////////////////////////////////////// // Function: PPCommandFile::PushFilename::Constructor diff --git a/ppremake/ppCommandFile.h b/ppremake/ppCommandFile.h index ee286bd7a7..92d4193a65 100644 --- a/ppremake/ppCommandFile.h +++ b/ppremake/ppCommandFile.h @@ -24,6 +24,8 @@ public: PPCommandFile(PPScope *scope); ~PPCommandFile(); + void set_output(ostream *out); + void set_scope(PPScope *scope); PPScope *get_scope() const; @@ -43,9 +45,11 @@ protected: bool handle_begin_command(); bool handle_forscopes_command(); bool handle_foreach_command(); + bool handle_formap_command(); bool handle_format_command(); bool handle_output_command(); - bool handle_defsub_command(); + bool handle_print_command(); + bool handle_defsub_command(bool is_defsub); bool handle_end_command(); bool handle_include_command(); @@ -57,13 +61,17 @@ protected: bool handle_define_command(); bool handle_set_command(); bool handle_map_command(); + bool handle_addmap_command(); bool include_file(const string &filename); bool replay_forscopes(const string &name); bool replay_foreach(const string &varname, const vector &words); + bool replay_formap(const string &varname, const string &mapvar); bool compare_output(const string &temp_name, const string &true_name); bool failed_if() const; + bool is_valid_formal(const string &formal_parameter_name) const; + private: class PushFilename { public: @@ -98,7 +106,10 @@ private: BS_nested_forscopes, BS_foreach, BS_nested_foreach, + BS_formap, + BS_nested_formap, BS_defsub, + BS_defun, BS_output }; diff --git a/ppremake/ppDirectoryTree.cxx b/ppremake/ppDirectoryTree.cxx index 0d772b3f12..ac9687c40b 100644 --- a/ppremake/ppDirectoryTree.cxx +++ b/ppremake/ppDirectoryTree.cxx @@ -90,22 +90,32 @@ PPDirectoryTree(const string &dirname, PPDirectoryTree *parent) : } //////////////////////////////////////////////////////////////////// -// Function: PPDirectoryTree::scan +// Function: PPDirectoryTree::scan_source // Access: Public -// Description: Reads in the complete hierarchy of source files. -// prefix is the pathname to the directory on disk, -// ending in slash. +// Description: Reads in the complete hierarchy of source files, +// beginning at the current directory. //////////////////////////////////////////////////////////////////// bool PPDirectoryTree:: -scan(const string &prefix, PPNamedScopes *named_scopes) { - if (!r_scan(prefix)) { +scan_source(PPNamedScopes *named_scopes) { + if (!r_scan("")) { return false; } - if (!read_source_file(prefix, named_scopes)) { + if (!read_source_file("", named_scopes)) { return false; } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PPDirectoryTree::scan_depends +// Access: Public +// Description: Reads in the depends file for each source file, and +// then sorts the files into dependency order. +//////////////////////////////////////////////////////////////////// +bool PPDirectoryTree:: +scan_depends(PPNamedScopes *named_scopes) { if (!read_depends_file(named_scopes)) { return false; } diff --git a/ppremake/ppDirectoryTree.h b/ppremake/ppDirectoryTree.h index f9a6e3981e..43add36d8d 100644 --- a/ppremake/ppDirectoryTree.h +++ b/ppremake/ppDirectoryTree.h @@ -33,7 +33,8 @@ protected: PPDirectoryTree(const string &dirname, PPDirectoryTree *parent); public: - bool scan(const string &prefix, PPNamedScopes *named_scopes); + bool scan_source(PPNamedScopes *named_scopes); + bool scan_depends(PPNamedScopes *named_scopes); int count_source_files() const; diff --git a/ppremake/ppMain.cxx b/ppremake/ppMain.cxx index 122decb117..33858fd723 100644 --- a/ppremake/ppMain.cxx +++ b/ppremake/ppMain.cxx @@ -8,6 +8,9 @@ #include "ppCommandFile.h" #include +#include +#include +#include // for perror //////////////////////////////////////////////////////////////////// // Function: PPMain::Constructor @@ -46,20 +49,17 @@ PPMain:: //////////////////////////////////////////////////////////////////// bool PPMain:: read_source(const string &root) { - // First, read the package file. We find this either in this - // directory, or in some directory above us. - string search = root + "/"; - if (root == ".") { - search = ""; - } + // First, find the top of the source tree, as indicated by the + // presence of a Package.pp file. + string trydir = root; - string package_file = search + PACKAGE_FILENAME; + string package_file = trydir + "/" + PACKAGE_FILENAME; while (access(package_file.c_str(), F_OK) != 0) { // We continue to walk up directories as long as we see a source // file in each directory. When we stop seeing source files, we // stop walking upstairs. - string source_file = search + SOURCE_FILENAME; + string source_file = trydir + "/" + SOURCE_FILENAME; if (access(source_file.c_str(), F_OK) != 0) { cerr << "Could not find ppremake package file " << PACKAGE_FILENAME << ".\n\n" @@ -69,24 +69,31 @@ read_source(const string &root) { << "important ppremake config files.\n\n"; return false; } - search += "../"; - package_file = search + PACKAGE_FILENAME; + trydir += "/.."; + package_file = trydir + "/" + PACKAGE_FILENAME; } + // Now cd to the source root and get the actual path. + if (chdir(trydir.c_str()) < 0) { + perror("chdir"); + return false; + } + + string cwd = get_cwd(); + cerr << "Root is " << cwd << "\n"; + _def_scope = new PPScope(&_named_scopes); _def_scope->define_variable("PACKAGEFILE", package_file); - _def_scope->define_variable("TOPDIRPREFIX", search); + _def_scope->define_variable("TOPDIR", cwd); _defs = new PPCommandFile(_def_scope); - // cerr << "Reading " << package_file << "\n"; - if (!_defs->read_file(package_file)) { - cerr << "Error reading package file " << package_file << ".\n"; + if (!_defs->read_file(PACKAGE_FILENAME)) { return false; } PPScope::push_scope(_def_scope); - if (!_tree.scan(search, &_named_scopes)) { + if (!_tree.scan_source(&_named_scopes)) { return false; } @@ -102,6 +109,17 @@ read_source(const string &root) { return false; } + cerr << "Read " << _tree.count_source_files() << " " << SOURCE_FILENAME + << " files.\n"; + + if (!read_global_file()) { + return false; + } + + if (!_tree.scan_depends(&_named_scopes)) { + return false; + } + return true; } @@ -191,3 +209,58 @@ p_process(PPDirectoryTree *dir) { return true; } + +//////////////////////////////////////////////////////////////////// +// Function: PPMain::read_global_file +// Access: Private +// Description: Reads in the Global.pp file after all sources files +// have been read and sorted into dependency order. +//////////////////////////////////////////////////////////////////// +bool PPMain:: +read_global_file() { + assert(_def_scope != (PPScope *)NULL); + + string global_filename = _def_scope->expand_variable("GLOBAL_FILE"); + if (global_filename.empty()) { + cerr << "No definition given for $[GLOBAL_FILE], cannot process.\n"; + return false; + } + + PPCommandFile global(_def_scope); + if (!global.read_file(global_filename)) { + cerr << "Error reading global definition file " + << global_filename << ".\n"; + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PPMain::get_cwd +// Access: Private, Static +// Description: Calls the system getcwd(), automatically allocating a +// large enough string. +//////////////////////////////////////////////////////////////////// +string PPMain:: +get_cwd() { + static size_t bufsize = 1024; + static char *buffer = NULL; + + if (buffer == (char *)NULL) { + buffer = new char[bufsize]; + } + + while (getcwd(buffer, bufsize) == (char *)NULL) { + if (errno != ERANGE) { + perror("getcwd"); + return string(); + } + delete[] buffer; + bufsize = bufsize * 2; + buffer = new char[bufsize]; + assert(buffer != (char *)NULL); + } + + return string(buffer); +} diff --git a/ppremake/ppMain.h b/ppremake/ppMain.h index cf226c816a..749fff6868 100644 --- a/ppremake/ppMain.h +++ b/ppremake/ppMain.h @@ -32,6 +32,8 @@ public: private: bool r_process_all(PPDirectoryTree *dir); bool p_process(PPDirectoryTree *dir); + bool read_global_file(); + static string get_cwd(); PPScope *_global_scope; diff --git a/ppremake/ppNamedScopes.cxx b/ppremake/ppNamedScopes.cxx index a42c9fad16..5ff5aafc31 100644 --- a/ppremake/ppNamedScopes.cxx +++ b/ppremake/ppNamedScopes.cxx @@ -5,6 +5,43 @@ #include "ppNamedScopes.h" #include "ppScope.h" +#include "ppDirectoryTree.h" + +#include +#include + +// An STL object to sort named scopes in order by dependency and then +// by directory name, used in sort_by_dependency(). +class SortScopesByDependencyAndName { +public: + bool operator () (const PPScope *a, const PPScope *b) const { + PPDirectoryTree *da = a->get_directory(); + PPDirectoryTree *db = b->get_directory(); + + // Scopes without associated directories appear first in the list. + bool da_is_null = (da == (PPDirectoryTree *)NULL); + bool db_is_null = (db == (PPDirectoryTree *)NULL); + + if (da_is_null != db_is_null) { + return da_is_null > db_is_null; + + } else if (da_is_null) { + // If two scopes have no associated directories (!) they are + // considered equivalent. + return false; + + } else { + // Otherwise, both scopes have associated directories, and we + // can properly put them in order by dependencies. + assert(da != (PPDirectoryTree *)NULL); + assert(db != (PPDirectoryTree *)NULL); + if (da->get_depends_index() != db->get_depends_index()) { + return da->get_depends_index() < db->get_depends_index(); + } + return da->get_dirname() < db->get_dirname(); + } + } +}; //////////////////////////////////////////////////////////////////// // Function: PPNamedScopes::Constructor @@ -83,6 +120,18 @@ get_scopes(const string &name, Scopes &scopes) const { } } +//////////////////////////////////////////////////////////////////// +// Function: PPNamedScopes::sort_by_dependency +// Access: Public, Static +// Description: Sorts the previously-generated list of scopes into +// order such that the later scopes depend on the +// earlier scopes. +//////////////////////////////////////////////////////////////////// +void PPNamedScopes:: +sort_by_dependency(PPNamedScopes::Scopes &scopes) { + sort(scopes.begin(), scopes.end(), SortScopesByDependencyAndName()); +} + //////////////////////////////////////////////////////////////////// // Function: PPNamedScopes::set_current // Access: Public diff --git a/ppremake/ppNamedScopes.h b/ppremake/ppNamedScopes.h index ec082b8738..0d869bfffd 100644 --- a/ppremake/ppNamedScopes.h +++ b/ppremake/ppNamedScopes.h @@ -29,6 +29,7 @@ public: PPScope *make_scope(const string &name); void get_scopes(const string &name, Scopes &scopes) const; + static void sort_by_dependency(Scopes &scopes); void set_current(const string &dirname); diff --git a/ppremake/ppScope.cxx b/ppremake/ppScope.cxx index 857f1ee3ce..a4ab053964 100644 --- a/ppremake/ppScope.cxx +++ b/ppremake/ppScope.cxx @@ -7,6 +7,8 @@ #include "ppNamedScopes.h" #include "ppFilenamePattern.h" #include "ppDirectoryTree.h" +#include "ppSubroutine.h" +#include "ppCommandFile.h" #include "tokenize.h" #include "find_searchpath.h" @@ -16,7 +18,7 @@ #include #include #include -#include // for perror(). +#include // for perror() and sprintf(). #include #include #include @@ -175,6 +177,10 @@ define_map_variable(const string &varname, const string &key_varname, return; } + if (key_varname.empty()) { + return; + } + vector names; tokenize_whitespace(scope_names, names); @@ -214,6 +220,71 @@ define_map_variable(const string &varname, const string &key_varname, define_variable(varname, repaste(results, " ")); } + +//////////////////////////////////////////////////////////////////// +// Function: PPScope::add_to_map_variable +// Access: Public +// Description: Adds a new key/scope pair to a previous map variable +// definition. +//////////////////////////////////////////////////////////////////// +void PPScope:: +add_to_map_variable(const string &varname, const string &key, + PPScope *scope) { + MapVariableDefinition &def = find_map_variable(varname); + if (&def == &_null_map_def) { + cerr << "Warning: undefined map variable: " << varname << "\n"; + return; + } + + def[key] = scope; + + // We need to do all this work to define the traditional expansion. + // Maybe not a great idea. + vector results; + MapVariableDefinition::const_iterator di; + for (di = def.begin(); di != def.end(); ++di) { + results.push_back((*di).first); + } + + set_variable(varname, repaste(results, " ")); +} + +//////////////////////////////////////////////////////////////////// +// Function: PPScope::define_formals +// Access: Public +// Description: Supplies values to a slew of variables at once, +// typically to define actual values for a list of +// formal parameters to a user-defined subroutine or +// function. +// +// Formals is a vector of variable names to be defined, +// and actuals is a comma-separated list of expressions +// to be substituted in, one-per-one. The +// subroutine_name is used only for error reporting. +//////////////////////////////////////////////////////////////////// +void PPScope:: +define_formals(const string &subroutine_name, + const vector &formals, const string &actuals) { + vector actual_words; + tokenize_params(actuals, actual_words, true); + + if (actual_words.size() < formals.size()) { + cerr << "Warning: not all parameters defined for " << subroutine_name + << ": " << actuals << "\n"; + } else if (actual_words.size() > formals.size()) { + cerr << "Warning: more parameters defined for " << subroutine_name + << " than actually exist: " << actuals << "\n"; + } + + for (int i = 0; i < (int)formals.size(); i++) { + if (i < (int)actual_words.size()) { + define_variable(formals[i], actual_words[i]); + } else { + define_variable(formals[i], string()); + } + } +} + //////////////////////////////////////////////////////////////////// // Function: PPScope::get_variable // Access: Public @@ -222,6 +293,12 @@ define_map_variable(const string &varname, const string &key_varname, //////////////////////////////////////////////////////////////////// string PPScope:: get_variable(const string &varname) const { + // Is it a user-defined function? + const PPSubroutine *sub = PPSubroutine::get_func(varname); + if (sub != (const PPSubroutine *)NULL) { + return expand_function(varname, sub, string()); + } + string result; if (p_get_variable(varname, result)) { return result; @@ -256,6 +333,34 @@ expand_variable(const string &varname) const { return expand_string(get_variable(varname)); } +//////////////////////////////////////////////////////////////////// +// Function: PPScope::find_map_variable +// Access: Public +// Description: Looks for the map variable definition in this scope +// or some ancestor scope. Returns the map variable +// definition if it is found, or _null_map_def if it is +// not. +//////////////////////////////////////////////////////////////////// +PPScope::MapVariableDefinition &PPScope:: +find_map_variable(const string &varname) const { + MapVariableDefinition &def = p_find_map_variable(varname); + if (&def != &_null_map_def) { + return def; + } + + // No such map variable. Check the stack. + ScopeStack::reverse_iterator si; + for (si = _scope_stack.rbegin(); si != _scope_stack.rend(); ++si) { + MapVariableDefinition &def = (*si)->p_find_map_variable(varname); + if (&def != &_null_map_def) { + return def; + } + } + + // Nada. + return _null_map_def; +} + //////////////////////////////////////////////////////////////////// // Function: PPScope::get_directory // Access: Public @@ -384,66 +489,9 @@ get_bottom_scope() { return _scope_stack.front(); } -//////////////////////////////////////////////////////////////////// -// Function: PPScope::p_set_variable -// Access: Private -// Description: The private implementation of p_set_variable. -// Returns true if the variable's definition is found -// and set, false otherwise. -//////////////////////////////////////////////////////////////////// -bool PPScope:: -p_set_variable(const string &varname, const string &definition) { - Variables::iterator vi; - vi = _variables.find(varname); - if (vi != _variables.end()) { - (*vi).second = definition; - return true; - } - - if (_parent_scope != (PPScope *)NULL) { - return _parent_scope->p_set_variable(varname, definition); - } - - return false; -} - -//////////////////////////////////////////////////////////////////// -// Function: PPScope::p_get_variable -// Access: Private -// Description: The private implementation of get_variable(). This -// checks the local scope only; it does not check the -// stack. It returns true if the variable is defined, -// false otherwise.. -//////////////////////////////////////////////////////////////////// -bool PPScope:: -p_get_variable(const string &varname, string &result) const { - Variables::const_iterator vi; - vi = _variables.find(varname); - if (vi != _variables.end()) { - result = (*vi).second; - return true; - } - - if (varname == "RELDIR" && - _directory != (PPDirectoryTree *)NULL && - current_output_directory != (PPDirectoryTree *)NULL) { - // $[RELDIR] is a special variable name that evaluates to the - // relative directory of the current scope to the current output - // directory. - result = current_output_directory->get_rel_to(_directory); - return true; - } - - if (_parent_scope != (PPScope *)NULL) { - return _parent_scope->p_get_variable(varname, result); - } - - return false; -} - //////////////////////////////////////////////////////////////////// // Function: PPScope::tokenize_params -// Access: Private +// Access: Public // Description: Separates a string into tokens based on comma // delimiters, e.g. for parameters to a function. // Nested variable references are skipped correctly, @@ -497,6 +545,75 @@ tokenize_params(const string &str, vector &tokens, } } +//////////////////////////////////////////////////////////////////// +// Function: PPScope::p_set_variable +// Access: Private +// Description: The private implementation of p_set_variable. +// Returns true if the variable's definition is found +// and set, false otherwise. +//////////////////////////////////////////////////////////////////// +bool PPScope:: +p_set_variable(const string &varname, const string &definition) { + Variables::iterator vi; + vi = _variables.find(varname); + if (vi != _variables.end()) { + (*vi).second = definition; + return true; + } + + if (_parent_scope != (PPScope *)NULL) { + return _parent_scope->p_set_variable(varname, definition); + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: PPScope::p_get_variable +// Access: Private +// Description: The private implementation of get_variable(). This +// checks the local scope only; it does not check the +// stack. It returns true if the variable is defined, +// false otherwise.. +//////////////////////////////////////////////////////////////////// +bool PPScope:: +p_get_variable(const string &varname, string &result) const { + Variables::const_iterator vi; + vi = _variables.find(varname); + if (vi != _variables.end()) { + result = (*vi).second; + return true; + } + + if (varname == "RELDIR" && + _directory != (PPDirectoryTree *)NULL && + current_output_directory != (PPDirectoryTree *)NULL) { + // $[RELDIR] is a special variable name that evaluates to the + // relative directory of the current scope to the current output + // directory. + result = current_output_directory->get_rel_to(_directory); + return true; + } + + if (varname == "DEPENDS_INDEX" && + _directory != (PPDirectoryTree *)NULL) { + // $[DEPENDS_INDEX] is another special variable name that + // evaluates to the numeric sorting index assigned to this + // directory based on its dependency relationship with other + // directories. It's useful primarily for debugging. + char buffer[32]; + sprintf(buffer, "%d", _directory->get_depends_index()); + result = buffer; + return true; + } + + if (_parent_scope != (PPScope *)NULL) { + return _parent_scope->p_get_variable(varname, result); + } + + return false; +} + //////////////////////////////////////////////////////////////////// // Function: PPScope::r_expand_string // Access: Private @@ -639,18 +756,27 @@ r_expand_variable(const string &str, size_t &vp, } string params = varname.substr(p); - // Is it a built-in function? + // Is it a user-defined function? + const PPSubroutine *sub = PPSubroutine::get_func(funcname); + if (sub != (const PPSubroutine *)NULL) { + return expand_function(funcname, sub, params); + } + // Is it a built-in function? if (funcname == "wildcard") { return expand_wildcard(params); } else if (funcname == "isdir") { return expand_isdir(params); + } else if (funcname == "isfile") { + return expand_isfile(params); } else if (funcname == "libtest") { return expand_libtest(params); } else if (funcname == "bintest") { return expand_bintest(params); } else if (funcname == "shell") { return expand_shell(params); + } else if (funcname == "standardize") { + return expand_standardize(params); } else if (funcname == "firstword") { return expand_firstword(params); } else if (funcname == "patsubst") { @@ -681,8 +807,12 @@ r_expand_variable(const string &str, size_t &vp, return expand_upcase(params); } else if (funcname == "downcase") { return expand_downcase(params); + } else if (funcname == "cdefine") { + return expand_cdefine(params); } else if (funcname == "closure") { return expand_closure(params); + } else if (funcname == "unmapped") { + return expand_unmapped(params); } // It must be a map variable. @@ -700,6 +830,7 @@ r_expand_variable(const string &str, size_t &vp, } // And now expand the variable. + string expansion; // Check for a special inline patsubst operation, like GNU make: @@ -866,6 +997,39 @@ expand_isdir(const string ¶ms) const { return result; } +//////////////////////////////////////////////////////////////////// +// Function: PPScope::expand_isfile +// Access: Private +// Description: Expands the "isfile" function variable. This +// returns true if the parameter exists and is a +// regular file, or false otherwise. This actually +// expands the parameter(s) with shell globbing +// characters, similar to the "wildcard" function, and +// looks only at the first expansion. +//////////////////////////////////////////////////////////////////// +string PPScope:: +expand_isfile(const string ¶ms) const { + vector results; + glob_string(expand_string(params), results); + + if (results.empty()) { + // No matching file, too bad. + return string(); + } + + const string &filename = results[0]; + struct stat stbuf; + + string result; + if (stat(filename.c_str(), &stbuf) == 0) { + if (S_ISREG(stbuf.st_mode)) { + result = filename; + } + } + + return result; +} + //////////////////////////////////////////////////////////////////// // Function: PPScope::expand_libtest // Access: Private @@ -1109,6 +1273,64 @@ expand_shell(const string ¶ms) const { } +//////////////////////////////////////////////////////////////////// +// Function: PPScope::expand_standardize +// Access: Private +// Description: Expands the "standardize" function variable. This +// converts the filename to standard form by removing +// consecutive repeated slashes and collapsing /../ +// where possible. +//////////////////////////////////////////////////////////////////// +string PPScope:: +expand_standardize(const string ¶ms) const { + string filename = expand_string(params); + if (filename.empty()) { + return string(); + } + + vector components; + + // Pull off the components of the filename one at a time. + bool global = (filename[0] == '/'); + + size_t p = 0; + while (p < filename.length() && filename[p] == '/') { + p++; + } + while (p < filename.length()) { + size_t slash = filename.find('/', p); + string component = filename.substr(p, slash - p); + if (component == ".") { + // Ignore /./. + } else if (component == ".." && !components.empty() && + !(components.back() == "..")) { + // Back up. + components.pop_back(); + } else { + components.push_back(component); + } + + p = slash; + while (p < filename.length() && filename[p] == '/') { + p++; + } + } + + // Now reassemble the filename. + string result; + if (global) { + result = "/"; + } + if (!components.empty()) { + result += components[0]; + for (int i = 1; i < (int)components.size(); i++) { + result += "/" + components[i]; + } + } + + return result; +} + //////////////////////////////////////////////////////////////////// // Function: PPScope::expand_firstword // Access: Private @@ -1408,9 +1630,13 @@ expand_unique(const string ¶ms) const { } //////////////////////////////////////////////////////////////////// -// Function: PPScope::expand_eq +// Function: PPScope::expand_if // Access: Private -// Description: Expands the "if" function variable. +// Description: Expands the "if" function variable. This evaluates +// the first parameter and returns the second parameter +// if the result is true (i.e. nonempty) and the third +// parameter (if present) if the result is faluse +// (i.e. empty). //////////////////////////////////////////////////////////////////// string PPScope:: expand_if(const string ¶ms) const { @@ -1424,7 +1650,7 @@ expand_if(const string ¶ms) const { } else { return ""; } - } else if (tokens.size() == 2) { + } else if (tokens.size() == 3) { if (!tokens[0].empty()) { return tokens[1]; } else { @@ -1515,6 +1741,7 @@ expand_not(const string ¶ms) const { // Access: Private // Description: Expands the "or" function variable. This returns // nonempty if any of its arguments are nonempty. +// Specifically, it returns the first nonempty argument. //////////////////////////////////////////////////////////////////// string PPScope:: expand_or(const string ¶ms) const { @@ -1525,10 +1752,10 @@ expand_or(const string ¶ms) const { vector::const_iterator ti; for (ti = tokens.begin(); ti != tokens.end(); ++ti) { if (!(*ti).empty()) { - return "1"; + return (*ti); } } - return ""; + return string(); } //////////////////////////////////////////////////////////////////// @@ -1536,6 +1763,7 @@ expand_or(const string ¶ms) const { // Access: Private // Description: Expands the "and" function variable. This returns // nonempty if all of its arguments are nonempty. +// Specifically, it returns the last argument. //////////////////////////////////////////////////////////////////// string PPScope:: expand_and(const string ¶ms) const { @@ -1546,10 +1774,15 @@ expand_and(const string ¶ms) const { vector::const_iterator ti; for (ti = tokens.begin(); ti != tokens.end(); ++ti) { if ((*ti).empty()) { - return ""; + return string(); } } - return "1"; + + if (tokens.empty()) { + return "1"; + } else { + return tokens.back(); + } } //////////////////////////////////////////////////////////////////// @@ -1582,6 +1815,33 @@ expand_downcase(const string ¶ms) const { return result; } +//////////////////////////////////////////////////////////////////// +// Function: PPScope::expand_cdefine +// Access: Private +// Description: Expands the "cdefine" function variable. This is a +// convenience function to output a C-style #define or +// #undef statement based on the value of the named +// variable. If the named string is a variable whose +// definition is nonempty, this returns "#define varname +// definition". Otherwise, it returns "#undef varname". +// This is particularly useful for building up a +// config.h file. +//////////////////////////////////////////////////////////////////// +string PPScope:: +expand_cdefine(const string ¶ms) const { + string varname = trim_blanks(params); + string expansion = trim_blanks(expand_variable(varname)); + + string result; + if (expansion.empty()) { + result = "#undef " + varname; + } else { + result = "#define " + varname + " " + expansion; + } + + return result; +} + //////////////////////////////////////////////////////////////////// // Function: PPScope::expand_closure // Access: Private @@ -1596,15 +1856,21 @@ expand_closure(const string ¶ms) const { vector tokens; tokenize_params(params, tokens, false); - if (tokens.size() != 2) { - cerr << "closure requires two parameters.\n"; + if (tokens.size() != 2 && tokens.size() != 3) { + cerr << "closure requires two or three parameters.\n"; return string(); } // The first parameter is the map variable name, the second - // parameter is the expression to close. + // parameter is the expression to evaluate, and the third parameter + // (if present) is the expression that leads to the recursive + // evaluation of the map variable. string varname = expand_string(tokens[0]); string expression = tokens[1]; + string close_on = expression; + if (tokens.size() > 2) { + close_on = tokens[2]; + } const MapVariableDefinition &def = find_map_variable(varname); if (&def == &_null_map_def) { @@ -1619,16 +1885,21 @@ expand_closure(const string ¶ms) const { // we also need to keep track of all the partial results we have yet // to evaluate (hence the vector of strings). set closure; - vector partial_results; + vector results; + vector next_pass; - partial_results.push_back(expand_string(expression)); + // Start off with the expression evaluated within the starting + // scope. + results.push_back(expand_string(expression)); - while (!partial_results.empty()) { + next_pass.push_back(expand_string(close_on)); + + while (!next_pass.empty()) { // Pull off one of the partial results (it doesn't matter which // one), and chop it up into its constituent words. vector pass; - tokenize_whitespace(partial_results.back(), pass); - partial_results.pop_back(); + tokenize_whitespace(next_pass.back(), pass); + next_pass.pop_back(); // And then map each of those words into scopes. vector::const_iterator wi; @@ -1636,30 +1907,121 @@ expand_closure(const string ¶ms) const { const string &word = (*wi); bool inserted = closure.insert(word).second; if (inserted) { - // This is a new word, which presumably maps to a scope. What - // does the expression evaluate to within that scope? - - MapVariableDefinition::const_iterator mvi; - mvi = def.find(word); - if (mvi != def.end()) { - PPScope *scope = (*mvi).second; - partial_results.push_back(scope->expand_string(expression)); + // This is a new word, which presumably maps to a scope. + MapVariableDefinition::const_iterator di; + di = def.find(word); + if (di != def.end()) { + PPScope *scope = (*di).second; + // Evaluate the expression within this scope. + results.push_back(scope->expand_string(expression)); + + // What does close_on evaluate to within this scope? That + // points us to the next scope(s). + next_pass.push_back(scope->expand_string(close_on)); } } } } - // Now we have the complete transitive closure of $[mapvar expression]. + // Now we have the complete transitive closure of $[mapvar close_on]. + string result = repaste(results, " "); + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: PPScope::expand_unmapped +// Access: Private +// Description: Expands the "closure" function variable. This is a +// special function that returns all the arguments to a +// map variable, unchanged, that did *not* match any of +// the keys in the map. +//////////////////////////////////////////////////////////////////// +string PPScope:: +expand_unmapped(const string ¶ms) const { + // Split the string up into tokens based on the commas. + vector tokens; + tokenize_params(params, tokens, false); + + if (tokens.size() != 2) { + cerr << "unmapped requires two parameters.\n"; + return string(); + } + + // The first parameter is the map variable name, and the second + // parameter is the space-separated list of arguments to the map. + string varname = expand_string(tokens[0]); + vector keys; + tokenize_whitespace(expand_string(tokens[1]), keys); + + const MapVariableDefinition &def = find_map_variable(varname); + if (&def == &_null_map_def) { + cerr << "Warning: undefined map variable: " << varname << "\n"; + return string(); + } + vector results; - set::const_iterator ci; - for (ci = closure.begin(); ci != closure.end(); ++ci) { - results.push_back(*ci); + vector::const_iterator ki; + for (ki = keys.begin(); ki != keys.end(); ++ki) { + MapVariableDefinition::const_iterator di; + di = def.find(*ki); + if (di == def.end()) { + // This key was undefined. + results.push_back(*ki); + } } string result = repaste(results, " "); return result; } +//////////////////////////////////////////////////////////////////// +// Function: PPScope::expand_function +// Access: Private +// Description: Expands the user-defined function reference. This +// invokes the nested commands within the function body, +// and returns all the output text as one line. Quite a +// job, really. +//////////////////////////////////////////////////////////////////// +string PPScope:: +expand_function(const string &funcname, + const PPSubroutine *sub, const string ¶ms) const { + PPScope::push_scope((PPScope *)this); + PPScope nested_scope(_named_scopes); + nested_scope.define_formals(funcname, sub->_formals, params); + + // This won't compile on VC++. It has only ostringstream, which is + // functionally equivalent but has a slightly different interface. + ostrstream ostr; + + PPCommandFile command(&nested_scope); + command.set_output(&ostr); + + command.begin_read(); + bool okflag = true; + vector::const_iterator li; + for (li = sub->_lines.begin(); li != sub->_lines.end() && okflag; ++li) { + okflag = command.read_line(*li); + } + if (okflag) { + okflag = command.end_read(); + } + + PPScope::pop_scope(); + + // Now get the output. We split it into words and then reconnect + // it, to replace all whitespace with spaces. + ostr << ends; + char *str = ostr.str(); + + vector results; + tokenize_whitespace(str, results); + + string result = repaste(results, " "); + delete[] str; + + return result; +} + //////////////////////////////////////////////////////////////////// // Function: PPScope::expand_map_variable // Access: Private @@ -1725,48 +2087,22 @@ expand_map_variable(const string &varname, const string &expression, return result; } -//////////////////////////////////////////////////////////////////// -// Function: PPScope::find_map_variable -// Access: Private -// Description: Looks for the map variable definition in this scope -// or some ancestor scope. -//////////////////////////////////////////////////////////////////// -const PPScope::MapVariableDefinition &PPScope:: -find_map_variable(const string &varname) const { - const MapVariableDefinition &def = p_find_map_variable(varname); - if (&def != &_null_map_def) { - return def; - } - - // No such map variable. Check the stack. - ScopeStack::reverse_iterator si; - for (si = _scope_stack.rbegin(); si != _scope_stack.rend(); ++si) { - const MapVariableDefinition &def = (*si)->p_find_map_variable(varname); - if (&def != &_null_map_def) { - return def; - } - } - - // Nada. - return _null_map_def; -} - //////////////////////////////////////////////////////////////////// // Function: PPScope::p_find_map_variable // Access: Private // Description: The implementation of find_map_variable() for a // particular static scope, without checking the stack. //////////////////////////////////////////////////////////////////// -const PPScope::MapVariableDefinition &PPScope:: +PPScope::MapVariableDefinition &PPScope:: p_find_map_variable(const string &varname) const { MapVariables::const_iterator mvi; mvi = _map_variables.find(varname); if (mvi != _map_variables.end()) { - return (*mvi).second; + return (MapVariableDefinition &)(*mvi).second; } if (_parent_scope != (PPScope *)NULL) { - return _parent_scope->find_map_variable(varname); + return _parent_scope->p_find_map_variable(varname); } return _null_map_def; diff --git a/ppremake/ppScope.h b/ppremake/ppScope.h index 75b925f2c1..efb9c32932 100644 --- a/ppremake/ppScope.h +++ b/ppremake/ppScope.h @@ -13,6 +13,7 @@ class PPNamedScopes; class PPDirectoryTree; +class PPSubroutine; /////////////////////////////////////////////////////////////////// // Class : PPScope @@ -23,6 +24,8 @@ class PPDirectoryTree; //////////////////////////////////////////////////////////////////// class PPScope { public: + typedef map MapVariableDefinition; + PPScope(PPNamedScopes *named_scopes); PPNamedScopes *get_named_scopes() const; @@ -35,9 +38,14 @@ public: void define_map_variable(const string &varname, const string &definition); void define_map_variable(const string &varname, const string &key_varname, const string &scope_names); + void add_to_map_variable(const string &varname, const string &key, + PPScope *scope); + void define_formals(const string &subroutine_name, + const vector &formals, const string &actuals); string get_variable(const string &varname) const; string expand_variable(const string &varname) const; + MapVariableDefinition &find_map_variable(const string &varname) const; PPDirectoryTree *get_directory() const; void set_directory(PPDirectoryTree *directory); @@ -49,6 +57,11 @@ public: static PPScope *pop_scope(); static PPScope *get_bottom_scope(); + void tokenize_params(const string &str, vector &tokens, + bool expand) const; + + static MapVariableDefinition _null_map_def; + private: class ExpandedVariable { public: @@ -56,14 +69,9 @@ private: ExpandedVariable *_next; }; - typedef map MapVariableDefinition; - bool p_set_variable(const string &varname, const string &definition); bool p_get_variable(const string &varname, string &result) const; - void tokenize_params(const string &str, vector &tokens, - bool expand) const; - string r_expand_string(const string &str, ExpandedVariable *expanded) const; string r_scan_variable(const string &str, size_t &vp) const; string r_expand_variable(const string &str, size_t &vp, @@ -73,9 +81,11 @@ private: string expand_wildcard(const string ¶ms) const; string expand_isdir(const string ¶ms) const; + string expand_isfile(const string ¶ms) const; string expand_libtest(const string ¶ms) const; string expand_bintest(const string ¶ms) const; string expand_shell(const string ¶ms) const; + string expand_standardize(const string ¶ms) const; string expand_firstword(const string ¶ms) const; string expand_patsubst(const string ¶ms) const; string expand_filter(const string ¶ms) const; @@ -91,14 +101,16 @@ private: string expand_and(const string ¶ms) const; string expand_upcase(const string ¶ms) const; string expand_downcase(const string ¶ms) const; + string expand_cdefine(const string ¶ms) const; string expand_closure(const string ¶ms) const; + string expand_unmapped(const string ¶ms) const; + string expand_function(const string &funcname, const PPSubroutine *sub, + const string ¶ms) const; string expand_map_variable(const string &varname, const string ¶ms) const; string expand_map_variable(const string &varname, const string &expression, const vector &keys) const; - const MapVariableDefinition & - find_map_variable(const string &varname) const; - const MapVariableDefinition & + MapVariableDefinition & p_find_map_variable(const string &varname) const; void glob_string(const string &str, vector &results) const; @@ -112,7 +124,6 @@ private: typedef map MapVariables; MapVariables _map_variables; - static MapVariableDefinition _null_map_def; PPScope *_parent_scope; typedef vector ScopeStack; diff --git a/ppremake/ppSubroutine.cxx b/ppremake/ppSubroutine.cxx index e2299271f3..a6e97d6421 100644 --- a/ppremake/ppSubroutine.cxx +++ b/ppremake/ppSubroutine.cxx @@ -6,6 +6,7 @@ #include "ppSubroutine.h" PPSubroutine::Subroutines PPSubroutine::_subroutines; +PPSubroutine::Subroutines PPSubroutine::_functions; //////////////////////////////////////////////////////////////////// // Function: PPSubroutine::define_sub @@ -46,3 +47,48 @@ get_sub(const string &name) { return (*si).second; } } + +//////////////////////////////////////////////////////////////////// +// Function: PPSubroutine::define_func +// Access: Public, Static +// Description: Adds a function to the global list with the +// indicated name. This is similar to a subroutine +// except it is to be invoked via a variable reference, +// instead of by a #call function. It cannot be +// shadowed by a local variable; it will always override +// any variable definition. +// +// The subroutine pointer must have been recently +// allocated, and ownership of the pointer will be +// passed to the global list; it may later delete it if +// another subroutine is defined with the same name. +//////////////////////////////////////////////////////////////////// +void PPSubroutine:: +define_func(const string &name, PPSubroutine *sub) { + Subroutines::iterator si; + si = _functions.find(name); + if (si == _functions.end()) { + _functions.insert(Subroutines::value_type(name, sub)); + } else { + delete (*si).second; + (*si).second = sub; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PPSubroutine::get_func +// Access: Public, Static +// Description: Returns the previously-defined function with the +// given name, or NULL if there is no such function +// with that name. +//////////////////////////////////////////////////////////////////// +const PPSubroutine *PPSubroutine:: +get_func(const string &name) { + Subroutines::const_iterator si; + si = _functions.find(name); + if (si == _functions.end()) { + return NULL; + } else { + return (*si).second; + } +} diff --git a/ppremake/ppSubroutine.h b/ppremake/ppSubroutine.h index a51dfd97e2..4672ca8730 100644 --- a/ppremake/ppSubroutine.h +++ b/ppremake/ppSubroutine.h @@ -20,14 +20,19 @@ //////////////////////////////////////////////////////////////////// class PPSubroutine { public: + vector _formals; vector _lines; public: static void define_sub(const string &name, PPSubroutine *sub); static const PPSubroutine *get_sub(const string &name); + static void define_func(const string &name, PPSubroutine *sub); + static const PPSubroutine *get_func(const string &name); + typedef map Subroutines; static Subroutines _subroutines; + static Subroutines _functions; }; #endif diff --git a/ppremake/ppremake.h b/ppremake/ppremake.h index 09be351a5d..5541618926 100644 --- a/ppremake/ppremake.h +++ b/ppremake/ppremake.h @@ -14,9 +14,11 @@ #ifdef HAVE_IOSTREAM #include #include +#include #else #include #include +#include #endif #include