* Tracked down the mkdepend tool which Ingo used in his updated makefile-engine

which auto-generates dependencies. It was written by Lars Duening for BeOS
  and uses libglob, which is also part of make. To re-use libglob and since
  make is already part of the Haiku tree, I added mkdepend to the bin tools.
* Added Lars Duening's copyright to AboutSystem.
* Added skeleton makefile and makefile-engine to data/develop.
* Added mkdepend and makefile-engine files to the Development optional package.
  It could be argued to move the make bin command there too, from it's current
  location in the HaikuImage file. However, make could be useful to always
  have available.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29609 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2009-03-19 12:19:41 +00:00
parent d15b54c97f
commit 432ce3738d
24 changed files with 5504 additions and 0 deletions

View File

@ -197,6 +197,21 @@ if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 {
# cc and c++ wrapper scripts
AddFilesToHaikuImage beos bin : cc c++ ;
# mkdepend build tool, which is part of the Haiku source tree
# (same as make, but make is already included independent of the
# Development package)
AddFilesToHaikuImage beos bin : mkdepend ;
# skeleton makefile and makefile-engine
local makefileEngineFiles =
<makefile-engine>makefile
<makefile-engine>makefile-engine
;
SEARCH on $(makefileEngineFiles)
= [ FDirName $(HAIKU_TOP) data develop ] ;
AddFilesToHaikuImage develop etc
: $(makefileEngineFiles) ;
# headers
AddHeaderDirectoryToHaikuImage gnu : 3rdparty ;
AddHeaderDirectoryToHaikuImage os ;

120
data/develop/makefile Normal file
View File

@ -0,0 +1,120 @@
## BeOS Generic Makefile v2.2 ##
## Fill in this file to specify the project being created, and the referenced
## makefile-engine will do all of the hard work for you. This handles both
## Intel and PowerPC builds of the BeOS and Haiku.
## Application Specific Settings ---------------------------------------------
# specify the name of the binary
NAME=
# specify the type of binary
# APP: Application
# SHARED: Shared library or add-on
# STATIC: Static library archive
# DRIVER: Kernel Driver
TYPE=
# add support for new Pe and Eddie features
# to fill in generic makefile
#%{
# @src->@
# specify the source files to use
# full paths or paths relative to the makefile can be included
# all files, regardless of directory, will have their object
# files created in the common object directory.
# Note that this means this makefile will not work correctly
# if two source files with the same name (source.c or source.cpp)
# are included from different directories. Also note that spaces
# in folder names do not work well with this makefile.
SRCS=
# specify the resource files to use
# full path or a relative path to the resource file can be used.
RSRCS=
# @<-src@
#%}
# end support for Pe and Eddie
# specify additional libraries to link against
# there are two acceptable forms of library specifications
# - if your library follows the naming pattern of:
# libXXX.so or libXXX.a you can simply specify XXX
# library: libbe.so entry: be
#
# - if your library does not follow the standard library
# naming scheme you need to specify the path to the library
# and it's name
# library: my_lib.a entry: my_lib.a or path/my_lib.a
LIBS=
# specify additional paths to directories following the standard
# libXXX.so or libXXX.a naming scheme. You can specify full paths
# or paths relative to the makefile. The paths included may not
# be recursive, so include all of the paths where libraries can
# be found. Directories where source files are found are
# automatically included.
LIBPATHS=
# additional paths to look for system headers
# thes use the form: #include <header>
# source file directories are NOT auto-included here
SYSTEM_INCLUDE_PATHS =
# additional paths to look for local headers
# thes use the form: #include "header"
# source file directories are automatically included
LOCAL_INCLUDE_PATHS =
# specify the level of optimization that you desire
# NONE, SOME, FULL
OPTIMIZE=
# specify any preprocessor symbols to be defined. The symbols will not
# have their values set automatically; you must supply the value (if any)
# to use. For example, setting DEFINES to "DEBUG=1" will cause the
# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG"
# would pass "-DDEBUG" on the compiler's command line.
DEFINES=
# specify special warning levels
# if unspecified default warnings will be used
# NONE = supress all warnings
# ALL = enable all warnings
WARNINGS =
# specify whether image symbols will be created
# so that stack crawls in the debugger are meaningful
# if TRUE symbols will be created
SYMBOLS =
# specify debug settings
# if TRUE will allow application to be run from a source-level
# debugger. Note that this will disable all optimzation.
DEBUGGER =
# specify additional compiler flags for all files
COMPILER_FLAGS =
# specify additional linker flags
LINKER_FLAGS =
# specify the version of this particular item
# (for example, -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL")
# This may also be specified in a resource.
APP_VERSION =
# (for TYPE == DRIVER only) Specify desired location of driver in the /dev
# hierarchy. Used by the driverinstall rule. E.g., DRIVER_PATH = video/usb will
# instruct the driverinstall rule to place a symlink to your driver's binary in
# ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will appear at
# /dev/video/usb when loaded. Default is "misc".
DRIVER_PATH =
## include the makefile-engine
include $(BUILDHOME)/etc/makefile-engine

View File

@ -0,0 +1,361 @@
## BeOS and Haiku Generic Makefile Engine v2.2.0
## Does all the hard work for the Generic Makefile
## which simply defines the project parameters
## Supports Generic Makefile v2.0, 2.01, 2.1, 2.2
# determine wheather running on x86 or ppc
MACHINE=$(shell uname -m)
ifeq ($(MACHINE), BePC)
CPU = x86
else
CPU = ppc
endif
# set the directory where object files and binaries will be created
OBJ_DIR := obj.$(CPU)
# create some default settings
ifeq ($(NAME), )
NAME = NameThisApp
endif
ifeq ($(TYPE), )
TYPE = APP
endif
ifeq ($(DRIVER_PATH), )
DRIVER_PATH = misc
endif
# specify that the binary should be created in the object directory
# NOTE: make doesn't find the target if its name is enclosed in
# quotation marks
# TARGET := "$(OBJ_DIR)/$(NAME)"
TARGET := $(OBJ_DIR)/$(NAME)
# specify the mimeset tool
MIMESET := mimeset
# specify the tools for adding and removing resources
XRES = xres
# platform specific settings
# x86 Settings
ifeq ($(CPU), x86)
# set the compiler and compiler flags
CC = gcc
# SETTING: set the CFLAGS for each binary type
ifeq ($(TYPE), DRIVER)
CFLAGS += -D_KERNEL_MODE=1 -no-fpic
else
CFLAGS +=
endif
# SETTING: set the proper optimization level
ifeq ($(OPTIMIZE), FULL)
OPTIMIZER = -O3
else
ifeq ($(OPTIMIZE), SOME)
OPTIMIZER = -O1
else
ifeq ($(OPTIMIZE), NONE)
OPTIMIZER = -O0
else
# OPTIMIZE not set so set to full
OPTIMIZER = -O3
endif
endif
endif
# SETTING: set proper debugger flags
ifeq ($(DEBUGGER), TRUE)
DEBUG += -g
OPTIMIZER = -O0
endif
CFLAGS += $(OPTIMIZER) $(DEBUG)
# SETTING: set warning level
ifeq ($(WARNINGS), ALL)
CFLAGS += -Wall -Wno-multichar -Wno-ctor-dtor-privacy
else
ifeq ($(WARNINGS), NONE)
CFLAGS += -w
endif
endif
# set the linker and linker flags
LD = gcc
LDFLAGS += $(DEBUG)
# SETTING: set linker flags for each binary type
ifeq ($(TYPE), APP)
LDFLAGS += -Xlinker -soname=_APP_
else
ifeq ($(TYPE), SHARED)
LDFLAGS += -nostart -Xlinker -soname=$(NAME)
else
ifeq ($(TYPE), DRIVER)
LDFLAGS += -nostdlib /boot/develop/lib/x86/_KERNEL_
endif
endif
endif
else
# ppc Settings
ifeq ($(CPU), ppc)
# set the compiler and compiler flags
CC = mwcc
CFLAGS +=
# SETTING: set the proper optimization level
ifeq ($(OPTIMIZE), FULL)
OPTIMIZER = -O7
else
ifeq ($(OPTIMIZE), SOME)
OPTIMIZER = -O3
else
ifeq ($(OPTIMIZE), NONE)
OPTIMIZER = -O0
else
# OPTIMIZE not set so set to full
OPTIMIZER = -O7
endif
endif
endif
#set the proper debugger settings
ifeq ($(DEBUGGER), TRUE)
DEBUG += -g
endif
CFLAGS += $(OPTIMIZER) $(DEBUG)
# SETTING: set warning level
ifeq ($(WARNINGS), ALL)
CFLAGS += -w on -requireprotos
else
ifeq ($(WARNINGS), NONE)
CFLAGS += -w off
endif
endif
# clear the standard environment variable
# now there are no standard libraries to link against
BELIBFILES=
# set the linker and linker flags
LD = mwldppc
# SETTING: set linker flags for each binary type
ifeq ($(TYPE), APP)
LDFLAGS +=
else
ifeq ($(TYPE), SHARED)
LDFLAGS += -xms
endif
endif
ifeq ($(TYPE), DRIVER)
LDFLAGS += -nodefaults \
-export all \
-G \
/boot/develop/lib/ppc/glue-noinit.a \
/boot/develop/lib/ppc/_KERNEL_
else
LDFLAGS += -export pragma \
-init _init_routine_ \
-term _term_routine_ \
-lroot \
/boot/develop/lib/ppc/glue-noinit.a \
/boot/develop/lib/ppc/init_term_dyn.o \
/boot/develop/lib/ppc/start_dyn.o
endif
# SETTING: output symbols in an xMAP file
ifeq ($(SYMBOLS), TRUE)
LDFLAGS += -map $(TARGET).xMAP
endif
# SETTING: output debugging info to a .SYM file
ifeq ($(DEBUGGER), TRUE)
LDFLAGS += -g -osym $(TARGET).SYM
endif
endif
endif
# psuedo-function for converting a list of source files in SRCS variable
# to a corresponding list of object files in $(OBJ_DIR)/xxx.o
# The "function" strips off the src file suffix (.ccp or .c or whatever)
# and then strips of the directory name, leaving just the root file name.
# It then appends the .o suffix and prepends the $(OBJ_DIR)/ path
define SRCS_LIST_TO_OBJS
$(addprefix $(OBJ_DIR)/, $(addsuffix .o, $(foreach file, $(SRCS), \
$(basename $(notdir $(file))))))
endef
define SRCS_LIST_TO_DEPENDS
$(addprefix $(OBJ_DIR)/, $(addsuffix .d, $(foreach file, $(SRCS), \
$(basename $(notdir $(file))))))
endef
OBJS = $(SRCS_LIST_TO_OBJS)
DEPENDS = $(SRCS_LIST_TO_DEPENDS)
# create a unique list of paths to our sourcefiles
SRC_PATHS += $(sort $(foreach file, $(SRCS), $(dir $(file))))
# add source paths to VPATH if not already present
VPATH :=
VPATH += $(addprefix :, $(subst ,:, $(filter-out $($(subst, :, ,$(VPATH))), $(SRC_PATHS))))
# SETTING: build the local and system include paths
ifeq ($(CPU), x86)
LOC_INCLUDES = $(foreach path, $(SRC_PATHS) $(LOCAL_INCLUDE_PATHS), $(addprefix -I, $(path)))
SYS_INCLUDES += -I-
SYS_INCLUDES += $(foreach path, $(SYSTEM_INCLUDE_PATHS), $(addprefix -I, $(path)))
else
ifeq ($(CPU), ppc)
LOC_INCLUDES = $(foreach path, $(SRC_PATHS) $(LOCAL_INCLUDE_PATHS), $(addprefix -I, $(path)))
SYS_INCLUDES += -i-
SYS_INCLUDES += $(foreach path, $(SYSTEM_INCLUDE_PATHS), $(addprefix -i , $(path)))
endif
endif
INCLUDES = $(LOC_INCLUDES) $(SYS_INCLUDES)
# SETTING: add the -L prefix to all library paths to search
LINK_PATHS = $(foreach path, $(SRC_PATHS) $(LIBPATHS), \
$(addprefix -L, $(path)))
# SETTING: specify the additional libraries to link against
# if the libraries have a .so or .a prefix, or if they are _APP_ or _KERNEL_
# simply add them to the list
LINK_LIBS += $(filter %.so %.a _APP_ _KERNEL_, $(LIBS))
# if the libraries do not have suffixes and are not _APP_ or _KERNEL_
# prepend -l to each name: be becomes -lbe
LINK_LIBS += $(foreach lib, $(filter-out %.so %.a _APP_ _KERNEL_, $(LIBS)), $(addprefix -l, $(lib)))
# add to the linker flags
LDFLAGS += $(LINK_PATHS) $(LINK_LIBS)
# SETTING: add the defines to the compiler flags
CFLAGS += $(foreach define, $(DEFINES), $(addprefix -D, $(define)))
# SETTING: add the additional compiler flags
CFLAGS += $(COMPILER_FLAGS)
# SETTING: add the additional linker flags
LDFLAGS += $(LINKER_FLAGS)
# SETTING: use the archive tools if building a static library
# otherwise use the linker
ifeq ($(TYPE), STATIC)
BUILD_LINE = ar -cru "$(TARGET)" $(OBJS)
else
BUILD_LINE = $(LD) -o $@ $(OBJS) $(LDFLAGS)
endif
# create the resource instruction
ifeq ($(RSRCS), )
DO_RSRCS :=
else
DO_RSRCS := $(XRES) -o "$(TARGET)" $(RSRCS)
endif
# define the actual work to be done
default: $(TARGET)
$(TARGET): $(OBJ_DIR) $(OBJS) $(RSRCS)
$(BUILD_LINE)
$(DO_RSRCS)
$(MIMESET) -f $@
# rule to create the object file directory if needed
$(OBJ_DIR)::
@[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1
# rules to make the dependency files
$(OBJ_DIR)/%.d : %.c
[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1; \
mkdepend $(LOC_INCLUDES) -p .c:$(OBJ_DIR)/%n.o -m -f $@ $<
$(OBJ_DIR)/%.d : %.cpp
[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1; \
mkdepend $(LOC_INCLUDES) -p .cpp:$(OBJ_DIR)/%n.o -m -f $@ $<
$(OBJ_DIR)/%.d : %.cp
[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1; \
mkdepend $(LOC_INCLUDES) -p .cp:$(OBJ_DIR)/%n.o -m -f $@ $<
$(OBJ_DIR)/%.d : %.cc
[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1; \
mkdepend $(LOC_INCLUDES) -p .cc:$(OBJ_DIR)/%n.o -m -f $@ $<
$(OBJ_DIR)/%.d : %.C
[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1; \
mkdepend $(LOC_INCLUDES) -p .C:$(OBJ_DIR)/%n.o -m -f $@ $<
$(OBJ_DIR)/%.d : %.CC
[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1; \
mkdepend $(LOC_INCLUDES) -p .CC:$(OBJ_DIR)/%n.o -m -f $@ $<
$(OBJ_DIR)/%.d : %.CPP
[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1; \
mkdepend $(LOC_INCLUDES) -p .CPP:$(OBJ_DIR)/%n.o -m -f $@ $<
-include $(DEPENDS)
# rules to make the object files
$(OBJ_DIR)/%.o : %.c
$(CC) -c $< $(INCLUDES) $(CFLAGS) -o $@
$(OBJ_DIR)/%.o : %.cpp
$(CC) -c $< $(INCLUDES) $(CFLAGS) -o $@
$(OBJ_DIR)/%.o : %.cp
$(CC) -c $< $(INCLUDES) $(CFLAGS) -o $@
$(OBJ_DIR)/%.o : %.cc
$(CC) -c $< $(INCLUDES) $(CFLAGS) -o $@
$(OBJ_DIR)/%.o : %.C
$(CC) -c $< $(INCLUDES) $(CFLAGS) -o $@
$(OBJ_DIR)/%.o : %.CC
$(CC) -c $< $(INCLUDES) $(CFLAGS) -o $@
$(OBJ_DIR)/%.o : %.CPP
$(CC) -c $< $(INCLUDES) $(CFLAGS) -o $@
# rules to handle lex/flex and yacc/bison files
$(OBJ_DIR)/%.o: %.l
flex $<
$(CC) -c $(INCLUDES) $(CFLAGS) lex.yy.c -o $@
$(OBJ_DIR)/%.o: %.y
bison -d -y $<
$(CC) -c $(INCLUDES) $(CFLAGS) y.tab.c -o $@
# empty rule. Things that depend on this rule will always get triggered
FORCE:
# The generic clean command. Delete everything in the object folder.
clean :: FORCE
-rm -rf $(OBJ_DIR)
# remove just the application from the object folder
rmapp ::
-rm -f $(TARGET)
# make it easy to install drivers for testing
USER_BIN_PATH = /boot/home/config/add-ons/kernel/drivers/bin
USER_DEV_PATH = /boot/home/config/add-ons/kernel/drivers/dev
driverinstall ::
ifeq ($(TYPE), DRIVER)
copyattr --data $(OBJ_DIR)/$(NAME) $(USER_BIN_PATH)/$(NAME)
mkdir -p $(USER_DEV_PATH)/$(DRIVER_PATH)
ln -sf $(USER_BIN_PATH)/$(NAME) $(USER_DEV_PATH)/$(DRIVER_PATH)/$(NAME)
endif

View File

@ -788,6 +788,11 @@ AboutView::AboutView(const BRect &rect)
"All rights reserved.",
"http://tc.umn.edu/~ringx004");
// MkDepend 1.7 copyright (Makefile dependency generator)
AddCopyrightEntry("MkDepend",
"Copyright " B_UTF8_COPYRIGHT "1995-2001 Lars Düning. "
"All rights reserved.");
// OpenSound
// AddCopyrightEntry("OpenSound",
// "Copyright " B_UTF8_COPYRIGHT " 1996-2008 4Front Technologies ",

View File

@ -194,6 +194,7 @@ SubInclude HAIKU_TOP src bin listdev ;
SubInclude HAIKU_TOP src bin make ;
SubInclude HAIKU_TOP src bin makebootable ;
#SubInclude HAIKU_TOP src bin makeudfimage ;
SubInclude HAIKU_TOP src bin mkdepend ;
SubInclude HAIKU_TOP src bin mkdos ;
SubInclude HAIKU_TOP src bin mkfs ;
SubInclude HAIKU_TOP src bin multiuser ;

110
src/bin/mkdepend/HISTORY Normal file
View File

@ -0,0 +1,110 @@
** 14-Oct-2001, Lars Düning **
- RELEASE 1.7
- (main, args) New options '--no-warn-exit' to return a zero exitcode
('success') when a warning was generated (for use in Makefiles).
- (main, args) New options '--ignore-missing' to ignore missing include
files (apart from printing a diagnostic).
- (Makefile, libglob/Makefile) Added x86->PPC cross-compilation.
** 01-Mar-2000, Lars Düning **
- RELEASE 1.6
- (main, args, nodes) New option '--select' to narrow the dependency
generation to a few selected files.
- (Makefile, libglob/Makefile) Added crosscompilation PPC->x86.
** 03-Feb-1999, Lars Düning **
- (main, args) When out of memory, the error message also contains a slightly
cryptic hint where the program failed.
- (Makefile) The 'archive' target also creates a checksum file for the
archive, using the /bin/cksum command.
The .dependencies are included only when no 'clean' or 'clobber' is
requested (this solves the behavior Dianne noticed, that a 'make clean'
first recreates .dependencies only to delete it again).
** 02-Feb-1999, Lars Düning **
- (args.*) All information about an include directory is now combined
in one structure.
- (main.c, nodes.*) Rewrote the file identification and searching routines,
the old code failed to discriminate files which are included from
different directories.
- (util.*) New.
- (getargs.c) A long option matched even when only the first characters
were given. A test for the proper length corrected this.
** 25-Nov-1998, Lars Düning **
- (getargs.c) A long option matched even when only the first characters
were given. A test for the proper length corrected this.
** 01-Nov-1998, Lars Düning **
- (getargs.c) If a value for an option was missing, the parser printed
the wrong option name in the error message.
** 25-Oct-1998, Lars Düning **
- RELEASE 1.4.5
- (Makefile, libglob/Makefile) Adapted for R4 compilations.
- (Makefile) Improved the dependency generation: dependencies are
kept in the file .dependencies; and the rule is clever enough
to fall back to the compiler facilities if mkdepend is not
on the system.
- (getargs) Separated the commandline parser into here.
- (args) New options '--longhelp' to print a long help text, and
'--version' to print the program version.
'--include' distinguishes between normal and system include paths.
- (main) Default file suffixes now also cover a whole range of
C++ suffixes (.cc, .cpp, .cxx, .cc).
Filenames with embedded spaces are written in quotes.
- (nodes, reader, main) Added support for system includes.
** 15-Oct-1998, Lars Düning **
- (main.c) The name for the makefile backup was allocated one character
too short.
** 04-Jul-1998, Lars Düning **
- RELEASE 1.4
RCS-Name is 'Rel-1_4', State is 'Rel'.
- Converted the program to BeOS. I decided to not keep the old Amiga
code - it's available on Aminet and I won't further develop it anyway.
New files: LICENSE.
Changed files: Just about everything else.
- Added libglob/ for filename globbing.
** 02-Mar-1996, Lars Düning **
- RELEASE 1.3
- Oops, when confronted with target/source relations, MkDepend put the
source name into the dependency list as well. Though intentional, this
had the potential to confuse implicit make rules. Now this behaviour
is optional, triggered by specifying '+' with the object extension.
(main.c, args.ch)
- RCS tweaks to the Makefiles.
** 25-Feb-1996, Lars Düning **
- RELEASE 1.2
- main.c (output_tree, output): Added output of includers of a file.
- main.c (readfiles): If a file can't be found, it's users known so far
are printed in the warning notice.
- nodes.c,h: Added .pUsers (List of includers of this file) to the Node
structure, extended routines nodes_depend() and nodes_deplist()
accordingly.
- Put under RCS (the Makefiles still need tweaking for this, though).
** 04-Feb-1996, Lars Düning **
- main.c (output, getargs, main): The program is now able to write the
list of dependencies into a separate file as well.
- main.c (output_tree): New to write the dependency tree into a file.
- args.ch, main.c: Exported argument parsing into args.c.
- reader.c (reader_openrw): Immediate writing if no file to read is
opened is now possible.
** 13-Oct-1995, Lars Düning **
- RELEASE 1.1
- reader.c (reader_copymake2): Copies the remainder of the original
Makefile starting with the second tagline.
** 12-Oct-1995, Lars Düning **
- main.c (make_objname): %p pattern expanded to %[-][<][<number>]p.
- Makefile, DMakefile: Making the 'archive' missed some files.
** 18-Sep-1995, Lars Düning **
- RELEASE 1.0

14
src/bin/mkdepend/Jamfile Normal file
View File

@ -0,0 +1,14 @@
SubDir HAIKU_TOP src bin mkdepend ;
SetSubDirSupportedPlatformsBeOSCompatible ;
SubDirHdrs [ FDirName $(SUBDIR) .. make glob ] ;
BinCommand mkdepend :
args.c
getargs.c
main.c
reader.c
nodes.c
util.c
: <make>libglob.a : mkdepend.rdef ;

28
src/bin/mkdepend/LICENSE Normal file
View File

@ -0,0 +1,28 @@
MkDepend License
Copyright (c) 1995-2000, Lars Düning.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Modifications of the original software, in parts or as a whole,
must be clearly recognizable as such.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
$Id: LICENSE 1.2 Wed, 01 Mar 2000 21:15:40 -0700 lars $

View File

@ -0,0 +1,622 @@
$Id: MkDepend.doc 1.10 Wed, 01 Mar 2000 21:15:40 -0700 lars $
MkDepend 1.7
Copyright (c) 1995-2001 by Lars Düning
All Rights Reserved.
"Good information are hard to get. It is even more difficult to put
it into use." -- Sherlock Holmes
Introduction
------------
Makefiles are very useful in the development of larger program systems,
as they notate the various dependencies and associated needed actions
in a machine-useable notation. Unfortunately it's the most important
dependency between C sources and their includes which have to be
maintained by hand, a most boring and errorprone task.
MkDepend is one of those programs which attempt to automate this part
of development by scanning source files for includes and repeating this
step recursively until the complete transitive closure of included files
is determined. The found dependencies are then written into an existing
makefile, keeping it up to date, and/or into a separate file (the 'depfile')
for use by the makefile or for documentary purposes.
The advantage of using MkDepend instead of the built-in dependency
facilities of modern compilers is that (a) MkDepend is faster,
(b) simplifies the maintenance of multiple and/or portable Makefiles,
and (c) you can modify it for your special needs.
Usage
-----
MkDepend is a shell-only program, compiled for R4.5
mkdepend {-i|-I|--include <includepath>[::<symbol>]}
{-x|--except <filepattern>}
{-S|--select <filepattern>}
{-s|--suffix <src_ext>{,<src_ext>}[+][:<obj_ext>] | [+]:<obj_ext>}
{-p|--objpat <src_ext>{,<src_ext>}[+]:<obj_pattern>}
[-f|--file <makefile>]
[-d|--dep <depfile>]
[-l|--flat]
[-m|--ignore-missing]
[-w|--no-warn-exit]
[-v|--verbose]
[-h|-?|--help|--longhelp]
[-V|--version]
{<filename>}
All option keywords are case sensitive. The space between the short
form of the keywords and their operands may be omitted. For example
mkdepend -I/include
mkdepend -i /include
mkdepend -I=/include
mkdepend --include=/include
mkdepend --include /include
are all equivalent. Several short options may be combined, but only
one of them may take an argument, and it must be the last one. For
example:
mkdepend -vl
mkdepend -vf Makefile
are legal, but
mkdepend -fv Makefile
will be misunderstood as 'mkdepend -f=v Makefile'.
The option '--' is special in that it marks the end of all option
recognition. All following arguments are considered filenames even
if they start with '-' or '--'.
General Operation
-----------------
MkDepend is given a 'skeleton' of C source files and searches them for
included files. The includes found are recursively searched for includes
themselves, until the complete transitive closure has been determined.
MkDepend searches the includes first in the current directory, then in
the given paths (if any), imitating the C preprocessor's behaviour.
The files are scanned for include statements of the form
#include "filename"
#include <filename>
excluding those which are commented out using C-style /* */- or
C++-style //-comments. Every other content of the files is ignored.
After all includes have been found, the dependencies are written into
a makefile (creating it if necessary). The makefile is searched for
a line
# --- DO NOT MODIFY THIS LINE -- AUTO-DEPENDS FOLLOW ---
after which MkDepend adds the dependencies, overwriting old ones, then
terminating the dependencies with the line
# --- DO NOT MODIFY THIS LINE -- AUTO-DEPENDS PRECEDE ---
Text following the second tagline in the makefile is not modified.
If the first tagline is not found, the tagged dependencies are simply
appended to the file. Existing makefiles are modified by renaming it
to <origname>.bak and then re-creating the makefile by copying the
data not to be modified.
The found dependencies for the 'skeleton' files are written as
<skeleton> : <included file 1> <included file 2>...
Lines are limited to 80 chars, longer entries are folded into several
lines, ending each but the last line with a backslash (\). If a
name contains spaces, it is written within double quotes.
MkDepend can be taught to know about source/object file relationships
to be used in the entries written. E,g, the entry generated for a typical
C source file would be of the form
<skeleton>.o : <include 1> <include 2> ...
Includes appear with that path in the list under which MkDepend found
them. To support multi-platform development, replacement texts may
be specified for the paths which are then used instead in the output.
For documentary purposes MkDepend may additionally (or instead) write
the dependencies into a separate file, either as flat lists or in
tree form. Here it writes the 'a includes b' relationships in the
form "a <- b" as well as the 'b is included by a' relationsships
in the form "b -> a".
Selected-File Operation
-----------------------
MkDepend can be instructed just look for dependencies involving
some selected include files. This mode is activated by the use
of one or more '-S' arguments; and the output in this mode is
restricted to just the skeleton and the selected file.
For example, where a normal MkDepend run would generate
foobar.o : foobar.h yacc.tab.h main.h
call MkDepend with the argument '-S yacc.tab.h' would reduce this output
to
foobar.o : yacc.tab.h
In the Makefile, these selected dependencies are put between
# --- DO NOT MODIFY THIS LINE -- SELECTED AUTO-DEPENDS FOLLOW ---
# --- DO NOT MODIFY THIS LINE -- SELECTED AUTO-DEPENDS PRECEDE ---
delimiter lines, so that both kinds of operations can be used on the
same Makefile.
In addition, the output of the other dependency files is modified in
a similar way.
Arguments
---------
<filepattern>
Any command argument not recognizable as option is considered as
specification of one of the 'skeleton' sources.
Wildcards are recognized.
Default: *.c
Example:
mkdepend *.c *.cc grammar.y
All files ending in ".c" or ".cc" and the file "grammar.y"
are considered.
The expansion of the wildcards is done by the shell.
------
-x <filepattern>
--except <filepattern>
Files which are not part of the 'skeleton', even if they are specified
as such. The filepattern may contain the typical bash-wildcards, which
are expanded by MkDepend.
Example:
mkdepend *.c -x 'test*'
All files ending in ".c", except those whose name start with "test",
are considered as sources. Note the quotes around "test*" to protect
it from shell name expansion.
------
-S <filepattern>
--select <filepattern>
The output of dependency information is restricted to just those
'skeleton' source which include at least one of the <filepattern> files.
Furthermore, only the named files are printed in the dependency lists.
The filepattern may contain the typical bash-wildcards, which are
expanded by MkDepend _against the files existing at the time of
program start_. The pattern has to match the full filename
of the included file, including the directory part implicitely given
by any -I argument.
Example:
mkdepend *.c -S 'yacc.tab.h'
Only the files which include "yacc.tab.h" will be listed in the
output.
------
-I <includedir>[::<symbol>]}
--include <includedir>[::<symbol>]}
Specify a directory to be searched for include files. The paths are
searched in the order given on the command line. Unless '-I-' was
specified, the directory the including file is in is searched first.
If <symbol> is specified, it replaces the <includedir> when writing
dependencies to a makefile.
Usually, the path, made up from all given <includedir>s, is searched
fully for both ""- and <>-includes. This behaviour changes if the
path is split using the special dirname '-' (like in '-I-').
If '-I-' is used, all directories given before the '-I-' are searched
only for ""-includes. The directories given after the '-I-' are
searched for both ""- and <>-includes again. Also the directories of
the including files are no longer searched automatically.
If a ""-include is not found, MkDepend will print a warning, but
still list the file in the generated dependencies. Missing <>-includes
on the other hand are silently ignored.
Example:
mkdepend -I /include -I- -I libglob
""-include files are searched in the current directory, in /include
and in libglob. <>-include files are searched only in the
current directory and libglob.
mkdepend -I '/include/pdlibs::$(PDLIBS)'
Include files are searched in the current directory and
in /include/pdlibs. A file like "/include/pdlibs/tree.h" will be
written as "$(PDLIBS)tree.h" into the makefile.
Again note the use of quotes to keep the shell from expanding
the text '$(PDLIBS)'.
Note that the syntax of this option is similar, but not identical to
what most compilers expect. One example of an exception is the GNU
C-Compiler which distinguishes between '-I' and '-i' in meaning. It is
therefore advisable to only use the uppercase '-I' for both compiler
and MkDepend.
------
-s <src_ext>{,<src_ext>}[+][:<obj_ext>] | [+]:<obj_ext>}
--suffix <src_ext>{,<src_ext>}[+][:<obj_ext>] | [+]:<obj_ext>}
Specify a name relationship between source and object files.
If a source name ends in one of the given <src_ext>s, an Makefile entry
with the object name constructed using the associated <obj_ext>.
The <obj_ext> given with no associated <src_ext> serves as default
extension used for those <src_ext> which are given without own
<obj_ext>.
When constructing the dependency list for a defined source/object
relation, the sourcefile itself is not included in the list, as
usually implicit makerules take care of them. This can be overridden
by specifying the '+' sign (which is associated with the given source
extensions).
Default: -s :.o -s .c,.cc,.cpp,.cp,.cxx
Example:
mkdepend -s :.o -s '.c,.cc'
Default <obj_ext> is ".obj", which is used for files with the
extensions ".c" and ".cc".
------
-p <src_ext>{,<src_ext>}[+]:<obj_pattern>
--objpat <src_ext>{,<src_ext>}[+]:<obj_pattern>
Similar to SUFFIX, but allows more complicated name relations.
<obj_pattern> gives the object file name verbatim, using placeholders
for the actual filenames:
%s: the full sourcename (w/o suffix)
%p: the path part of the sourcename
%[-][<][<number>]p: the path part of the sourcename
<number>: skip the first <number> directories of the path,
defaults to 0.
< : count the directories from the end or the path part.
- : use, don't skip the counted directories.
%n: the base of the sourcename (w/o suffix)
%%: the character '%'.
%x: the character x for every other character.
Example:
mkdepend -p .c:obj/%n.o
For every sourcefile <name>.c, an entry for obj/<name>.o is
created.
mkdepend -p .c:obj/%1p%n.o 'source/*.c'
For every sourcefile source/<name>.c, an entry for obj/<name>.o is
created.
------
-f <makefile>
--file <makefile>
Specify the makefile to modify. If none is specified and the --dep
option is missing as well, MkDepend searches in order for "Makefile",
"makefile", "Makefile.mk", "makefile.mk" and "GNUMakefile". If none
of these exist, 'Makefile' is used and thus created.
------
-d <depfile>
--dep <depfile>
Specify the depfile to write the dependencies into.
The output hereinto notes just the plain dependencies between the
skeleton and the included files, i.e. ignores any --objpat or --objpat
setting. However, symbolic include paths are used here as well.
MkDepend prints both the 'a is included by b' as well as the
'b includes a' relationships. The former are tagged with '<-' in
the output, the latter with '->'.
If --flat is not specified, the dependencies are written in tree
form with indentation representating the nesting.
If --flat is specified, a flat list like that in Makefiles will
be written.
------
-l
--flat
Print the plain dependency file (see option --dep) as flat list instead
of tree form.
------
-m|--ignore-missing
If an include file is not found, it is NOT added to the dependencies.
However, MkDepend will still print diagnostic.
------
-w|--no-warn-exit
If MkDepend generates a warning, it does not return a non-zero exit
code to the caller (useful for use within makefiles).
------
-v
--verbose
Print some output during operation, namely the program name and the
file currently under examination.
------
-h
--help
--longhelp
Print a (short) summary of the commandline arguments and exit the
program.
------
-V
--version
Print the program version and exit.
Installation
------------
Copy the executable "mkdepend" into a suitable directory, profitably
into one in your search path. The PPC executable is in the subdirectory
obj.ppc/, the x86 executable in the subdirectory obj.x86/.
Using MkDepend
--------------
The straightforward use of MkDepend is of course the call from the
commandline a la 'mkdepend *.c', give or take a few command options. This
would scan all C source files, compute the dependencies and update the
Makefile in the same directory with these dependencies. Easy to use and
as easy to forget to do after an important change (trust me, it happens!).
Also, modifying the Makefile may not be what you want; after all, it adds
quite a bunch of junk to the file which is of no direct interest to you.
Let's solve the second problem first: the solution is to instruct MkDepend
to write all dependencies into an auxiliary file '.dependencies', which is
done with the '-f' command option. The command now looks like this:
'mkdepend -f .dependencies *.c'. To make use of this new file, the following
statement must be added to the Makefile on a separate line:
'-include .dependencies'. When make processes this line, it will read the
contents of .dependencies and treat them as if they were written in the
Makefile. The '-' in the command tells make to ignore the whole statement
should .dependencies not exist.
The solution to the first problem (calling MkDepend automatically whenever
a file changes) is to put the MkDepend call into the Makefile, too.
Fortunately for us, Be's standard make allows a Makefile to change itself
or any included file: if such a change is detected, make will simply
re-read the affected files. Putting MkDepend into a Makefile requires the
following changes/additions to be done (modified according to your special
needs where necessary):
- the main build rule for $(TARGET) must be changed to include .dependencies
as one of the requisites:
$(TARGET) : .dependencies $(OBJS) ...
- since MkDepend is not part of the BeOS distribution, the Makefile must
be able to use the normal compiler as a standin for MkDepend. The variable
DEP_FLAGS is set to the appropriate value to do so:
ifeq ($(CC), gcc)
DEP_FLAGS = -M
endif
ifeq ($(CC), mwcc$(CPU))
DEP_FLAGS = -make
endif
- the rule to generate the .dependencies file:
.dependencies: $(SRCS)
$(SHELL) -ec '\
if [ -n "`type -t mkdepend`" ]; then \
mkdepend $(SRCS) $(INCLUDES) -p '\''.c:obj.$$(CPU)/%n.o'\'' -f$@; \
else \
$(CC) $(DEP_FLAGS) $(INCLUDES) $(SRCS) \
| tr '\''\011'\'' '\''\040'\'' \
| sed '\''s;^\([^ :][^ :]*\);$$(OBJ)/\1;g'\'' > $@; \
fi'
- gmake automatically makes '.dependencies' when it is missing; however,
if our intent is to 'clean' all auxiliary files, this behaviour is
rather annoying. The solution is to include the .dependencies into
the Makefile only when no cleaning action is requested:
ifneq (,$(filter clean clobber cleanall clobberall, $MAKECMDGOALS))
-include .dependencies
endif
- a rule to point out missing header files (this allows a smoother make
process in case of outdated .dependencies):
%.h :
@echo "Warning: Can't find $@."
And that's all.
The same changes apply if you chose to let mkdepend modify the Makefile
directly, just replace every occurence of '.dependencies' with 'Makefile'
(and of course do not '-include Makefile' in your Makefile).
For a real-life example take a look at MkDepend's own Makefile.
Program Information
-------------------
MkDepend consists of these source files:
main.c,.h : Program control, data generation routines.
args.c,.h : Argument parsing.
getargs.c,.h : Generic commandline parser.
reader.c,.h : Reading of source files and scanning for #include statements.
Copying and writing of makefiles.
nodes.c,.h : Management of the names and locations of the files analysed.
It is implemented as a binary search tree with an additional
linked list.
util.c,.h : Some helpful functions - ok, right now just one function.
version.h : The version number, automatically updated by PRCS.
Filename expansion is provided by the static library libglob, which comes
under the GNU Library Public License in the subdirectory libglob/.
The provided Makefile takes care of all the necessary steps to compile and
link both MkDepend and the libglob. See the head comment of the Makefile
for further information about available targets and cross-compilation.
MkDepend was developed with Metrowerks C, Gnu C and GNU make; PRCS provides
the source code version management.
Bugs/TODO
---------
Maybe allow the modification of several makefiles with one call.
Maybe omit from the depends list those files that could not be found.
The Makefile should be more generic.
History
-------
v 1.6 (01-Mar-2000)
Added the possibility to select certain files for dependency generation.
v 1.5 (03-Feb-1999)
Added the search for include files in the directory of the including
file; older versions of MkDepend searched in the directory from where
MkDepend was started.
v 1.4.5 (25-Oct-1998)
R4 support (PPC and x86).
The version number is now handled by PRCS.
New command options '--longhelp' and '--version'.
Default file suffixes now also cover a whole range of
C++ suffixes (.cc, .cpp, .cxx, .cc).
Systemincludes (<>-includes) are now handled; with the help of
the new command option -i-.
Filenames with embedded spaces are quoted when written to a Makefile.
v 1.4 (04-Jul-1998) :
Moved to BeOS, Amiga support dropped.
New option -?|-h|--help for online help.
v 1.3 (02-Mar-1996) :
For source/object relations, the source is no longer included in
dependency list, except when demanded by '+'-command option.
v 1.2 (25-Feb-1996) :
New option -D=DEP/K for separate file with then plain source
dependencies.
New option -L=FLAT/S to write the plain dependencies as flat
list instead of a tree.
v 1.1 (13-Oct-1995) :
The dependencies may now be placed in midst of a makefile.
Object file name pattern %p expanded to %[-][<][<number>]p .
v 1.0 (18-Sep-1995) :
Initial release, at that time for Amiga OS.
Authors
-------
Lars Düning, 10 Morningside Gardens, Edinburgh, EH10 5LA, United Kingdom
EMail: lars@bearnip.com, or duening@ibr.cs.tu-bs.de (deprecated)
The file reader was inspired by the input module of lcc by David Hanson
and Christopher Fraser.
The elaborate %p pattern follows a suggestion by Michael A. Wiedmer
(<maw@paralax.demon.co.uk>).
The initial support for R4/x86 and a nice generic Makefile was provided
by Stephen van Egmond (<svanegmond@home.com>).
Dianne Kyra Hackborn (<hackbod@angryredplanet.com>) and
Stephen van Egmond provided valuable input.
Legalese
--------
The following license is replicated in the file LICENSE. It applies to
all files and derivates thereof which are part of the MkDepend package,
except for those files which explicitely state otherwise.
Copyright (c) 1995-1999, Lars Düning.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Modifications of the original software, of parts or of the whole,
must be clearly recognizable as such.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,21 @@
========================================================================
File: mkdepend-17.zip
Author: Lars Duening (lars@bearnip.com)
Release: 1.7 (14. Oct 2001)
Compatibility: R5
Location: contrib/development
Description: Dependencygenerator for Makefiles
Notes:
MkDepend scans C-source files recursively for includes and
writes the found dependency trees into an existing makefile.
Special features of MkDepend are:
- generates the complete transitive closure of all included files;
- searches the included files in several definable paths, and allows
to represent these pathnames by symbols in the generated Makefile;
- the source/object filename relationships may be flexibly defined;
- quite fast file scanner :-).
The archive comes with full source and precompiled executables for
both x86 and (cross-compiled) PPC.
========================================================================

670
src/bin/mkdepend/args.c Normal file
View File

@ -0,0 +1,670 @@
/* $Id: args.c 1.9 Wed, 01 Mar 2000 21:15:40 -0700 lars $ */
/*---------------------------------------------------------------------------
** Arguments parsing and variables.
**
** Copyright (c) 1996-2001 by Lars Düning. All Rights Reserved.
** This file is free software. For terms of use see the file LICENSE.
**---------------------------------------------------------------------------
** Parsed arguments:
**
** {-i|--include <includepath>[::<symbol>]}
** [-i-]
** {-x|--except <filepattern>}
** {-S|--select <filepattern>}
** {-s|--suffix <src_ext>{,<src_ext>}[+][:<obj_ext>] | [+]:<obj_ext>}
** {-p|--objpat <src_ext>{,<src_ext>}[+]:<obj_pattern>
** [-f|--file <makefile>]
** [-d|--dep <depfile>]
** [-l|--flat]
** [-m|--ignore-missing]
** [-w|--no-warn-exit]
** [-v|--verbose]
** [-h|-?|--help|--longhelp]
** [-V|--version]
** {<filename>}
**
**---------------------------------------------------------------------------
*/
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "args.h"
#include "getargs.h"
#include "main.h"
#include "glob.h"
#include "version.h"
/*-------------------------------------------------------------------------*/
/* Program arguments */
short bVerbose = FALSE; /* TRUE: Verbose action */
SArray aFiles = { 0, 0, NULL }; /* Source files */
SArray aAvoid = { 0, 0, NULL }; /* Source files to avoid */
SArray aSelect = { 0, 0, NULL }; /* Selected include files to print */
Include * aIncl = NULL; /* Include directories */
int iInclSize = 0; /* Number of valid entries in aIncl */
static int allocIncl = 0; /* Allcoated size of pIncl */
short bSplitPath = FALSE; /* TRUE: distinguish between normal
* and system include path. */
SArray aSrcExt = { 0, 0, NULL }; /* Source file extensions */
static int allocGiveSrc = 0, sizeGiveSrc = 0;
/* Allocated/used size of *bGiveSrc */
short * bGiveSrc = NULL; /* For each entry in aSrcExt:
* TRUE if the source name shall appear
* in the dependency list, too. */
SArray aObjExt = { 0, 0, NULL }; /* Associated object file extensions */
SArray aObjPat = { 0, 0, NULL }; /* Associated object file patterns */
char * sObjExt = NULL; /* Default object file extension */
short bDefGSrc = FALSE; /* For sObjExt: TRUE if the source
* name shall appear in the depency
* list, too */
char * sMake = NULL; /* Name of the Makefile */
char * sDepfile = NULL; /* Name of the dependency file */
short bFlat = FALSE; /* TRUE: Depfile in flat format */
short bNoWarnExit = FALSE; /* TRUE: Don't return RETURN_WARN
* from program */
short bIgnoreMiss = FALSE; /* TRUE: Ignore missing includes */
/*-------------------------------------------------------------------------*/
/* Every recognized option has a ordinal number */
typedef enum OptNumber {
cUnknown = OPTION_UNKNOWN /* unknown option */
, cArgument = OPTION_ARGUMENT /* normal argument (for us: filename) */
, cInclude /* --include */
, cExcept /* --except */
, cSelect /* --select */
, cSuffix /* --suffix */
, cObjPat /* --objpat */
, cFile /* --file */
, cDep /* --dep */
, cFlat /* --flat */
, cNoWarn // --no-warn-exit
, cIgnMiss // --ignore-missing
, cHelp /* --help */
, cLongHelp /* --longhelp */
, cVerbose /* --verbose */
, cVersion /* --version */
} OptNumber;
/* Comprehensive lists of recognized options */
static OptionDesc aOptions[]
= { { 'i', "include", cInclude, TRUE }
, { 'I', NULL, cInclude, TRUE }
, { 'x', "except", cExcept, TRUE }
, { 'S', "select", cSelect, TRUE }
, { 's', "suffix", cSuffix, TRUE }
, { 'p', "objpat", cObjPat, TRUE }
, { 'f', "file", cFile, TRUE }
, { 'd', "dep", cDep, TRUE }
, { 'l', "flat", cFlat, FALSE }
, { 'm', "ignore-missing", cIgnMiss, FALSE }
, { 'w', "no-warn-exit", cNoWarn, FALSE }
, { 'h', "help", cHelp, FALSE }
, { '?', NULL, cHelp, FALSE }
, { '\0', "longhelp", cLongHelp, FALSE }
, { 'v', "verbose", cVerbose, FALSE }
, { 'V', "version", cVersion, FALSE }
};
/*-------------------------------------------------------------------------*/
static void
version (void)
/* Print the version of the program. */
{
fputs("MkDepend " VERSION " - Makefile Dependency Generator\n"
"\nReleased: " RELEASE_DATE
"\nCompiled: " __DATE__
#ifdef __TIME__
" " __TIME__
#endif
"\n", stdout);
}
/*-------------------------------------------------------------------------*/
static void
shortusage (void)
/* Print the short help information to stdout. */
{
version();
printf("\nUsage: %s [options] <filename>...\n", aPgmName);
fputs(
"\nOptions are:\n"
"\n"
" -i|--include <includepath>[::<symbol>]\n"
" -x|--except <filepattern>\n"
" -S|--select <filepattern>\n"
" -s|--suffix <src_ext>{,<src_ext>}[+][:<obj_ext>]\n"
" -s|--suffix [+]:<obj_ext>\n"
" -p|--objpat <src_ext>{,<src_ext>}[+]:<obj_pattern>\n"
" -f|--file <makefile>\n"
" -d|--dep <depfile>\n"
" -l|--flat\n"
" -m|--ignore-missing\n"
" -w|--no-warn-exit\n"
" -v|--verbose\n"
" -h|-?|--help|--longhelp\n"
" -V|--version\n"
, stdout);
} /* shortusage() */
/*-------------------------------------------------------------------------*/
static void
usage (void)
/* Print the help information to stdout. */
{
version();
printf("\nUsage: %s [options] <filename>...\n", aPgmName);
fputs(
"\nOptions are:\n"
"\n"
" -i|--include <includepath>[::<symbol>]\n"
" Add <includepath> to the list of searched directories. If given,\n"
" <symbol> is used in the generated dependencies to denote\n"
" the <includepath>.\n"
" The special notation '-i-' is used to split the search path into\n"
" a non-system and a common part.\n"
"\n"
" -x|--except <filepattern>\n"
" Except all matching files from the root set.\n"
"\n"
" -S|--select <filepattern>\n"
" Only the dependencies for files including <filepattern> are printed,\n"
" and in those only the included files matching <filepattern> are listed.\n"
" Except all matching files from the root set.\n"
"\n"
" -s|--suffix <src_ext>{,<src_ext>}[+][:<obj_ext>]\n"
" Set the recognized source file suffixes (and optionally associated\n"
" object file suffixes).\n"
"\n"
" -s|--suffix [+]:<obj_ext>\n"
" Set the default object file suffix.\n"
"\n"
" -p|--objpat <src_ext>{,<src_ext>}[+]:<obj_pattern>\n"
" Define a complex source/object file name relation.\n"
" The <objpattern> recognizes as meta-symbols:\n"
" %s: the full sourcename (w/o suffix)\n"
" %[-][<][<number>]p: the path part of the sourcename\n"
" <number>: skip first <number> directories of the path,\n"
" defaults to 0.\n"
" < : directories are counted from the end.\n"
" - : use, don't skip the counted directories.\n"
" %n: the base of the sourcename (w/o suffix)\n"
" %%: the character %\n"
" %x: the character 'x' for every other character.\n"
"\n"
" -f|--file <makefile>\n"
" Update <makefile> with the found dependencies (default is 'Makefile').\n"
"\n"
" -d|--dep <depfile>\n"
" Write the found dependencies into <depfile>.\n"
"\n"
" -l|--flat\n"
" When generating a <depfile> write the dependencies in flat form.\n"
"\n"
" -m|--ignore-missing\n"
" If an include file is not found, it is NOT added to the dependencies.\n"
"\n"
" -w|--no-warn-exit\n"
" If MkDepend generates a warning, it does not return a non-zero exit\n"
" code to the caller (useful for use within makefiles).\n"
"\n"
" -v|--verbose\n"
" Verbose operation.\n"
"\n"
" -V|--version\n"
" Display the version of the program and exit.\n"
"\n"
" --longhelp\n"
" Display this help and exit.\n"
"\n"
" -h|-?|--help\n"
" Display the short help text and exit.\n"
"\n"
, stdout);
}
/*-------------------------------------------------------------------------*/
static int
givesrc_addflag (short bFlag)
/* Add <bFlag> to *bGiveSrc.
* Return 0 on success, non-0 on error.
*/
{
short * pFlags;
assert(sizeGiveSrc <= allocGiveSrc);
if (sizeGiveSrc+1 > allocGiveSrc)
{
pFlags = (short*)realloc(bGiveSrc, sizeof(short)*(allocGiveSrc+4));
if (!pFlags)
return 1;
bGiveSrc = pFlags;
allocGiveSrc += 4;
}
bGiveSrc[sizeGiveSrc] = bFlag;
sizeGiveSrc++;
return 0;
}
/*-------------------------------------------------------------------------*/
static int
include_addinfo (char * pPath, char * pSymbol, int bSystem)
/* Add the given data to to *bIncl.
* Return 0 on success, non-0 on error.
*/
{
Include * pNew;
assert(iInclSize <= allocIncl);
if (iInclSize+1 > allocIncl)
{
pNew = realloc(aIncl, sizeof(Include)*(allocIncl+4));
if (!pNew)
return 1;
aIncl = pNew;
allocIncl += 4;
}
aIncl[iInclSize].pPath = pPath;
aIncl[iInclSize].pSymbol = pSymbol;
aIncl[iInclSize].bSysPath = bSystem;
iInclSize++;
return 0;
}
/*-------------------------------------------------------------------------*/
int
array_addfile (SArray *pArray, const char * pName)
/* Add a copy of <*pName> to the string array <pArray>.
* Return 0 on success, non-0 on error.
* If pName is NULL, the array is simply extended by a NULL pointer.
*/
{
char ** pStrs;
assert(pArray->size <= pArray->alloc);
if (pArray->size+1 > pArray->alloc)
{
pStrs = (char **)realloc(pArray->strs, sizeof(char *)*(pArray->alloc+4));
if (!pStrs)
return 1;
pArray->strs = pStrs;
pArray->alloc += 4;
}
else
pStrs = pArray->strs;
if (pName)
{
pStrs[pArray->size] = strdup(pName);
if (!pStrs[pArray->size])
return 1;
}
else
pStrs[pArray->size] = NULL;
pArray->size++;
return 0;
}
/*-------------------------------------------------------------------------*/
int
array_addlist (SArray *pArray, int count, const char ** pList)
/* Add the <count> strings from <pList> to string array <pArray>.
* pList and contained strings may be freed after return.
* Return 0 on success, non-0 else.
*/
{
char ** pStrs;
int i;
assert(pList);
if (!count)
return 0;
assert(pArray->size <= pArray->alloc);
if (pArray->size+count > pArray->alloc)
{
pStrs = (char **)realloc(pArray->strs, sizeof(char *)*(pArray->alloc+count));
if (!pStrs)
return 1;
pArray->strs = pStrs;
pArray->alloc += count;
}
else
pStrs = pArray->strs;
for (i = 0; i < count; i++)
{
char * pString;
pString = strdup(pList[i]);
if (!pString)
return 1;
pStrs[pArray->size++] = pString;
}
return 0;
}
/*-------------------------------------------------------------------------*/
int
add_expfile (SArray *pArray, const char * pName)
/* Glob filename <*pName> and add the filenames to string array <pArray>.
* Return 0 on success, non-0 else.
*/
{
glob_t aGlob;
int rc;
memset(&aGlob, 0, sizeof(aGlob));
switch (glob(pName, GLOB_NOSORT|GLOB_BRACE|GLOB_TILDE, NULL, &aGlob))
{
case GLOB_NOSPACE:
globfree(&aGlob);
exit_nomem(" (add_expfile: glob)");
break;
case GLOB_ABORTED:
printf("%s: Error expanding %s\n", aPgmName, pName);
globfree(&aGlob);
set_rc(RETURN_ERROR, TRUE);
break;
case GLOB_NOMATCH:
globfree(&aGlob);
return 0;
case 0:
/* No error */
break;
default:
globfree(&aGlob);
exit_doserr(RETURN_ERROR);
break;
}
assert(aGlob.gl_pathc > 0);
rc = 0;
if (aGlob.gl_pathc > 0)
rc = array_addlist(pArray, aGlob.gl_pathc, (const char **)aGlob.gl_pathv);
globfree(&aGlob);
return rc;
}
/*-------------------------------------------------------------------------*/
static int
handler (int eOption, const char * pValue)
/* Callback function for getargs(). It is called when option <eOption>
* was recognized, possibly also passing an associated value in <pValue>.
* Return 0 on success, non-zero else.
*/
{
int i; /* All purpose */
switch (eOption)
{
case cArgument:
i = array_addfile(&aFiles, pValue);
if (i)
exit_nomem(" (args: add file)");
break;
case cInclude:
{
char * pSym, * pMark;
char * pVal;
/* Special case: check for the '-' marker */
if (!strcmp(pValue, "-"))
{
bSplitPath = TRUE;
break;
}
/* Since we're going to hack into pValue, possibly extending it
* by one character, we better make a copy of it. We need it
* anyway to store the data in aIncl[].
*/
pVal = malloc(strlen(pValue)+2);
if (!pVal)
exit_nomem(" (args: dup include arg)");
strcpy(pVal, pValue);
/* Allow for <path>::<symbol> notation */
pSym = NULL;
pMark = pVal+strlen(pVal);
if (pMark != pVal)
{
pMark--;
while (!pSym && pMark >= pVal+1)
{
if (':' != *pMark)
{
pMark--;
continue;
}
if (':' != *(pMark-1))
{
pMark -= 2;
continue;
}
pSym = pMark+1;
*(pMark-1) = '\0';
}
}
if (pSym && !strlen(pSym))
pSym = NULL;
else if (pSym)
{
pSym = strdup(pSym);
if (!pSym)
exit_nomem(" (args: dup include sym)");
}
/* Make sure <path> ends in a ':' or '/' */
pMark = pVal+strlen(pVal);
if (pMark > pVal && ':' != *(pMark-1) && '/' != *(pMark-1))
{
*pMark = '/';
*(pMark+1) = '\0';
}
i = include_addinfo(pVal, pSym, bSplitPath);
if (i)
exit_nomem(" (args: add include info)");
}
break;
case cExcept:
i = add_expfile(&aAvoid, pValue);
if (i)
exit_nomem(" (args: add except)");
break;
case cSelect:
i = add_expfile(&aSelect, pValue);
if (i)
exit_nomem(" (args: add select)");
break;
case cSuffix:
case cObjPat:
{
char * pMark, *pOsfix;
short bGotPlus;
/* Allow for <src_suffix>[+]:<obj_suffix> notation */
bGotPlus = FALSE;
pOsfix = NULL;
pMark = (char *)pValue+strlen(pValue);
if (pMark != pValue)
{
pMark--;
while (!pOsfix && pMark >= pValue)
{
if (':' != *pMark)
{
pMark--;
continue;
}
pOsfix = pMark+1;
if (pMark != pValue && *(pMark-1) == '+')
{
bGotPlus = TRUE;
pMark--;
}
*pMark = '\0';
}
}
if (pOsfix && !strlen(pOsfix))
pOsfix = NULL;
/* --objpat needs the [+]:<obj_pattern> part! */
if (cObjPat == eOption && !pOsfix)
{
printf("%s: <obj_pattern> not specified.\n", aPgmName);
set_rc(RETURN_ERROR, TRUE);
}
/* [+]:<obj_suffix> alone defines default object suffix */
if (pOsfix && !strlen(pValue))
{
if (sObjExt)
free(sObjExt);
sObjExt = strdup(pOsfix);
if (!sObjExt)
exit_nomem(" (args: dup obj suffix)");
bDefGSrc = bGotPlus;
}
else
{
char * pSfix;
/* Allow for <sfix1>,<sfix2>,...,<sfixn> for source suffixes */
for ( pSfix = (char *)pValue
; NULL != (pMark = strchr(pSfix, ','))
; pSfix = pMark+1
)
{
*pMark = '\0';
if (strlen(pSfix))
{
if ( array_addfile(&aSrcExt, pSfix)
|| givesrc_addflag(bGotPlus)
|| (cSuffix == eOption ? array_addfile(&aObjExt, pOsfix)
: array_addfile(&aObjPat, pOsfix)
)
)
exit_nomem(" (args: add obj suffix)");
}
}
if (strlen(pSfix))
{
if ( array_addfile(&aSrcExt, pSfix)
|| givesrc_addflag(bGotPlus)
|| (cSuffix == eOption ? array_addfile(&aObjExt, pOsfix)
: array_addfile(&aObjPat, pOsfix)
)
)
exit_nomem(" (args: add last obj suffix)");
}
}
}
break;
case cFile:
if (sMake)
free(sMake);
sMake = strdup(pValue);
if (!sMake)
exit_nomem(" (args: dup make)");
break;
case cDep:
if (sDepfile)
free(sDepfile);
sDepfile = strdup(pValue);
if (!sDepfile)
exit_nomem(" (args: dup dep)");
break;
case cFlat:
bFlat = TRUE;
break;
case cIgnMiss:
bIgnoreMiss = TRUE;
break;
case cNoWarn:
bNoWarnExit = TRUE;
break;
case cVerbose:
bVerbose = TRUE;
break;
case cHelp:
shortusage();
set_rc(RETURN_WARN, TRUE);
break;
case cLongHelp:
usage();
set_rc(RETURN_WARN, TRUE);
break;
case cVersion:
version();
set_rc(RETURN_WARN, TRUE);
break;
default:
/* This shouldn't happen. */
printf("%s: (getargs) Internal error, eOption is %d\n", aPgmName, eOption);
assert(0);
break;
}
return 0;
}
/*-------------------------------------------------------------------------*/
void
parseargs (int argc, char ** argv)
/* Get the arguments from the commandline and fill in the exported variables.
* In case of an error, the program is terminated.
*/
{
if (getargs(argc, argv, aOptions, handler))
set_rc(RETURN_ERROR, TRUE);
}
/***************************************************************************/

61
src/bin/mkdepend/args.h Normal file
View File

@ -0,0 +1,61 @@
/* $Id: args.h 1.6 Wed, 01 Mar 2000 21:15:40 -0700 lars $ */
/*---------------------------------------------------------------------------
* Copyright (c) 1999-2001 by Lars Düning. All Rights Reserved.
* This file is free software. For terms of use see the file LICENSE.
*---------------------------------------------------------------------------
*/
#ifndef __ARGS_H__
#define __ARGS_H__ 1
/* Dynamic string array */
typedef struct _sarray
{
int size; /* Number of used strings */
int alloc; /* Number of allocated string pointers */
char ** strs; /* Array of string pointers */
} SArray;
/* Information about one include directory */
typedef struct _inclinfo {
char * pPath; /* Pathname of the directory */
char * pSymbol; /* Symbol to use in Makefiles, NULL if none */
int bSysPath; /* TRUE for system directories */
} Include;
/* Program arguments */
extern short bVerbose; /* TRUE: Verbose action */
extern SArray aFiles; /* Source files */
extern SArray aAvoid; /* Source files to avoid */
extern SArray aSelect; /* Selected include files to print */
extern Include * aIncl; /* Include directory information */
extern int iInclSize; /* Number of valid entries in aIncl */
extern short bSplitPath; /* Include path handling */
extern SArray aSrcExt; /* Source file extensions */
extern SArray aObjExt; /* Associated object file extensions */
extern SArray aObjPat; /* Associated object file patterns */
extern short * bGiveSrc; /* For each entry in aSrcExt: TRUE if the
* source name shall appear in the
* dependency list, too. */
extern char * sObjExt; /* Default object file extension */
extern short bDefGSrc; /* For sObjExt: TRUE if the source name
* shall appear in the depency list, too
*/
extern char * sMake; /* Name of the Makefile */
extern char * sDepfile; /* Name of the dependency file */
extern short bFlat; /* TRUE: Depfile in flat format */
extern short bNoWarnExit; /* TRUE: Don't return RETURN_WARN from program */
extern short bIgnoreMiss; /* TRUE: Ignore missing includes */
/* Prototypes */
extern void parseargs (int argc, char ** argv);
extern int array_addlist (SArray *, int, const char **);
extern int array_addfile (SArray *, const char *);
extern int add_expfile (SArray *, const char *);
#endif

326
src/bin/mkdepend/getargs.c Normal file
View File

@ -0,0 +1,326 @@
/* $Id: getargs.c 1.5 Wed, 01 Mar 2000 21:15:40 -0700 lars $ */
/*---------------------------------------------------------------------------
* Commandline argument parser.
*
* Copyright (c) 1998-2000 by Lars Düning. All Rights Reserved.
* This file is free software. For terms of use see the file LICENSE.
*---------------------------------------------------------------------------
* This code parses the arguments passed to the program in the count <argc>
* and the array of strings <argv>. The parser distinguishes options, which
* start with a '-', from normal arguments; options are further distinguished
* by their name and may take an additional value. The parser neither
* imposes nor expects any order of options and arguments.
*
* Options are recognized in two forms. In the short form the option must
* be given as a single '-' followed by a single letter. In the long form,
* options start with '--' followed by a string of arbitrary length.
* Short options are case sensitive, long options aren't.
* Examples are: '-r' and '--recursive'.
*
* If an option takes a value, it must follow the option immediately after
* a separating space or '='. Additionally, the value for a short option
* may follow the option without separator. Examples are: '-fMakefile',
* '-f Makefile', '--file=Makefile' and '--file Makefile'.
*
* Short options may be collated into one argument, e.g. '-rtl', but
* of these only the last may take a value.
*
* The option '--' marks the end of options. All following command arguments
* are considered proper arguments even if they start with a '-' or '--'.
*-------------------------------------------------------------------------
* Internally every option recognized by the program is associated with
* an id number, assigned by the user. The parser itself uses the two
* id numbers 'OPTION_UNKNOWN' for unrecognized options, and
* 'OPTION_ARGUMENT' for proper command arguments.
*
* Id numbers are associated with their option strings/letters by the
* the array aOptions, which is passed to the parser function. Every element
* in this array is a structure defining the option's name (string
* or letter), the associated id number, and whether or not the option
* takes a value. An element can hold just one type of option (short or
* long) by setting the description the other option to \0 resp. NULL.
* The order of the elements does not matter. The end of the array is
* marked with an element using OPTION_UNKNOWN as assigned id number.
*
* The parsing is done by calling the function
*
* int getargs( int argc, char ** argv
* , const OptionDesc aOptions[]
* , OptionHandler handler)
*
* The function is passed the argument count <argc> and vector <argv> as
* they were received from the main() function, the option description
* array <aOptions> and a callback function* <handler>. getargs()
* returns 0 if the parsing completed successfully, and non-zero else.
*
* The handler function is called for every successfully recognized option
* and argument. Its prototype is
*
* int handler(int iOption, const char *pValue)
*
* Parameter <iOption> denotes the recognized option, and pValue points
* to the beginning of the value string if the option takes a value.
* Proper arguments are parsed with eOption==OPTION_ARGUMENT and pValue
* pointing to the argument string. The handler has to return 0 if the
* option/argument was processed correctly, and non-zero else.
*
* Additionally, getargs() puts the basename of the program (as determined
* by argv[0]) into the exported variable
*
* const char *aPgmName
*
* when called the first time.
*-------------------------------------------------------------------------
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "getargs.h"
const char *aPgmName = NULL;
/* The exported program name. */
#define MY_TRUE 1
#define MY_FALSE 0
/*-------------------------------------------------------------------------*/
int
getargs ( int argc, char ** argv
, OptionDesc aOptions[]
, OptionHandler opt_eval
)
/* Get the arguments from the commandline and pass them
* as (number, optional value) to the <opt_eval> callback.
* The options are defined by the array <aOptions>, with an OPTION_UNKNOWN
* element marking the last entry.
*
* If opt_eval() returns non-zero, argument scanning is terminated.
* In that case, or if getargs() detects an error itself, getargs() returns
* non-zero.
* A zero return means 'success' in both cases.
*
* Additionally, on the first call getargs() sets aPgmName to the basename
* of the program as derived from argv[0].
*/
{
int i; /* all purpose */
int nOptions; /* Number of options */
int iArg; /* Number of argument under inspection */
int eOption; /* The current recognized option */
int xOption; /* The index of the recog otion in aOptions */
short bCont; /* True: find another option in the same argument */
short bDone; /* True: all options parsed, only args left */
short bShort; /* True: current argument is a short option */
char * pArg; /* Next argument character to consider */
assert(aOptions != NULL);
assert(opt_eval != NULL);
/* Determine the program's name */
if (NULL == aPgmName)
{
char * newName;
newName = strdup(basename(argv[0]));
if (NULL == newName)
aPgmName = (const char *)argv[0];
else
aPgmName = (const char *)newName;
}
/* Make the compiler happy */
bShort = MY_FALSE;
pArg = NULL;
/* Count the options */
for (nOptions = 0; aOptions[nOptions].iNumber != OPTION_UNKNOWN; nOptions++)
/* SKIP */ ;
/* Scan all arguments */
bCont = MY_FALSE;
bDone = MY_FALSE;
for (iArg = 1; iArg < argc; !bCont ? iArg++ : iArg)
{
ssize_t iArglen; /* Length of remaining argument */
char * pValue; /* First character of an option value, or NULL */
int bTakesValue; /* This option takes a value */
/* Make the compiler happy */
iArglen = 0;
pValue = NULL;
bTakesValue = MY_FALSE;
if (bDone)
eOption = OPTION_ARGUMENT;
else
/* If this is not a continuation, reinitialise the inspection vars.
* For --opt=val arguments, pValue is set to the first character of val.
*/
if (!bCont)
{
pArg = argv[iArg];
if ('-' == pArg[0] && '-' == pArg[1]) /* Long option? */
{
eOption = OPTION_UNKNOWN;
bShort = MY_FALSE;
pArg += 2;
/* Special case: if the argument is just '--', it marks the
* end of all options.
* We set a flag and continue with the next argument.
*/
if ('\0' == *pArg)
{
bDone = MY_TRUE;
continue;
}
pValue = strchr(pArg, '=');
if (pValue != NULL)
{
iArglen = pValue - pArg;
pValue++;
}
else
iArglen = (signed)strlen(pArg);
}
else if ('-' == pArg[0]) /* Short option? */
{
eOption = OPTION_UNKNOWN;
bShort = MY_TRUE;
pArg++;
iArglen = (signed)strlen(pArg);
pValue = NULL;
}
else /* No option */
{
eOption = OPTION_ARGUMENT;
pValue = pArg;
iArglen = 0;
}
}
else
eOption = OPTION_UNKNOWN;
/* If the option is not determined yet, do it.
* Set pValue to the first character of the value if any.
*/
if (OPTION_UNKNOWN == eOption)
{
xOption = 0;
if (bShort) /* search the short option */
{
for (i = 0; i < nOptions; i++)
if ('\0' != aOptions[i].cOption && *pArg == aOptions[i].cOption)
{
xOption = i;
eOption = aOptions[i].iNumber;
bTakesValue = aOptions[i].bValue;
pArg++; iArglen--; /* Consume this character */
break;
}
/* Consume a following '=' if appropriate */
if (OPTION_UNKNOWN != eOption
&& bTakesValue
&& iArglen > 0 && '=' == *pArg)
{
pArg++; iArglen--;
}
/* If there is a value following in the same argument, set pValue to
* it and mark the remaining characters as 'consumed'
*/
if (OPTION_UNKNOWN != eOption && bTakesValue && iArglen > 0)
{
pValue = pArg;
pArg += iArglen;
iArglen = 0;
}
}
else /* search the long option */
{
for (i = 0; i < nOptions; i++)
if (NULL != aOptions[i].pOption
&& (size_t)iArglen == strlen(aOptions[i].pOption)
&& !strncasecmp(pArg, aOptions[i].pOption, (unsigned)iArglen))
{
xOption = i;
eOption = aOptions[i].iNumber;
bTakesValue = aOptions[i].bValue;
break;
}
}
if (OPTION_UNKNOWN == eOption)
{
fprintf(stderr, "%s: Unknown option '", aPgmName);
if (bShort)
fprintf(stderr, "-%c", *pArg);
else
fprintf(stderr, "--%*.*s", (int)iArglen, (int)iArglen, pArg);
fputs("'.\n", stderr);
return 1;
}
/* If at this point bTakesValue is true, but pValue is still NULL,
* then the value is in the next argument. Get it if it's there.
*/
if (bTakesValue && pValue == NULL && iArg + 1 < argc)
{
iArg++;
pValue = argv[iArg];
}
/* Signal an error if pValue is still NULL or if it's empty. */
if (bTakesValue && (pValue == NULL || !strlen(pValue)))
{
fprintf(stderr, "%s: Option '", aPgmName);
if (bShort)
putc(aOptions[xOption].cOption, stderr);
else
fputs(aOptions[xOption].pOption, stderr);
fputs("' expects a value.\n", stderr);
return 1;
}
} /* if (unknown option) */
/* Before evaluation of the parsed option, determine 'bCont' */
bCont = bShort && (iArglen > 0) && !bTakesValue;
/* --- The option evaluation --- */
i = (*opt_eval)(eOption, pValue);
if (i)
return i;
} /* for (iArg) */
return 0;
} /* getargs() */
/*-------------------------------------------------------------------------*/
char *
basename (const char *pName)
/* Find the basename (filename) in a UNIX-style pathname and return
* a pointer to its first character.
* Example: basename("/boot/home/data/l.txt") returns a pointer to "l.txt".
*/
{
char * pBase, * cp;
pBase = (char *)pName;
for (cp = (char *)pName; *cp; cp++)
if ('/' == *cp)
pBase = cp+1;
return pBase;
}
/***************************************************************************/

View File

@ -0,0 +1,37 @@
/* $Id: getargs.h 1.2 Wed, 01 Mar 2000 21:15:40 -0700 lars $ */
/*---------------------------------------------------------------------------
** Copyright (c) 1995-1998 by Lars Düning. All Rights Reserved.
** This file is free software. For terms of use see the file LICENSE.
**---------------------------------------------------------------------------
*/
#ifndef __GETARGS_H__
#define __GETARGS_H__ 1
/* Description of an option */
typedef struct OptionDesc {
unsigned char cOption; /* The option character (may be \0) */
char * pOption; /* The option string (may be NULL) */
int iNumber; /* The associated option number */
short bValue; /* True: option takes a value */
} OptionDesc;
/* Callback function type for option handling */
typedef int (*OptionHandler)(int iOption, const char * pValue);
/* Predefined values for OptionDesc.eNumber */
#define OPTION_UNKNOWN 0 /* Option unknown, or 'end of descriptor array' */
#define OPTION_ARGUMENT 1 /* Not an option, but a real argument */
/* --- Prototypes --- */
extern char * basename (const char *);
extern int getargs(int, char **, OptionDesc[], OptionHandler);
/* --- Variables --- */
extern const char * aPgmName;
#endif /* __GETARGS_H__ */

1503
src/bin/mkdepend/main.c Normal file

File diff suppressed because it is too large Load Diff

37
src/bin/mkdepend/main.h Normal file
View File

@ -0,0 +1,37 @@
/* $Id: main.h 1.4 Wed, 01 Mar 2000 21:15:40 -0700 lars $ */
/*---------------------------------------------------------------------------
** Copyright (c) 1995-2000 by Lars Düning. All Rights Reserved.
** This file is free software. For terms of use see the file LICENSE.
**---------------------------------------------------------------------------
*/
#ifndef __MAIN_H__
#define __MAIN_H__ 1
/* Return codes */
#define RETURN_OK 0 /* Everything is ok */
#define RETURN_WARN 1 /* A warning was issued */
#define RETURN_ERROR 2 /* An error occured */
#define RETURN_FAIL 3 /* A fatal error occured */
/* Boolean values */
#define FALSE 0
#define TRUE 1
/* Macros */
#define IS_SELECT_MODE (aSelect.size != 0)
/* The macro returns TRUE if only selected dependencies are to be
* generated.
*/
/* Prototypes */
extern void set_rc (int, int);
extern void exit_doserr (int);
extern void exit_nomem (char *);
#endif

View File

@ -0,0 +1,11 @@
resource app_version
{
major = 1,
middle = 7,
minor = 1,
variety = 5,
internal = 0,
short_info = "1.7.1",
long_info = "1.7.1 © 1995-2001 Lars Düning. All rights reserved."
};

587
src/bin/mkdepend/nodes.c Normal file
View File

@ -0,0 +1,587 @@
/* $Id: nodes.c 1.6 Wed, 01 Mar 2000 21:15:40 -0700 lars $ */
/*---------------------------------------------------------------------------
* Management of the dependency tree and nodes.
*
* Copyright (c) 1995-2000 by Lars Düning. All Rights Reserved.
* This file is free software. For terms of use see the file LICENSE.
*---------------------------------------------------------------------------
* Each file (source or include) is associated one node which is kept in
* a binary search tree with the name as index. Glued to each node is
* a list of that nodes which files the master nodes includes.
* Each node contains an extra node pointer the module uses to implement
* tree-independant lists, namely the TODO list of files still to read
* and a virtual stack for inorder tree traversals.
*
* Adding and retrieving the files to analyse is done using the functions
* nodes_addsource()
* nodes_depend()
* nodes_todo()
* nodes_select_mark()
*
* The output of the dependency tree is done inorder using
* nodes_initwalk()
* nodes_inorder()
*
* The list of dependencies for one single node is managed using
* nodes_deplist()
* nodes_freelist()
*
* Tree traversal and creation must not be mixed!
*---------------------------------------------------------------------------
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "main.h"
#include "nodes.h"
#include "util.h"
/*-------------------------------------------------------------------------*/
/* Types for block allocation of Nodes and NodeRefs.
* Note that Nodes are never freed.
*/
#define NBLOCKSIZE 16
typedef struct nodeblock
{
struct nodeblock * pNext; /* Next nodeblock */
int iFree; /* Number of first free node */
Node aNodes[NBLOCKSIZE]; /* Block of nodes */
}
NodeBlock;
#define RBLOCKSIZE 16
typedef struct refblock
{
struct refblock * pNext; /* Next refblock */
int iFree; /* Number of first free noderef */
NodeRef aRefs[NBLOCKSIZE]; /* Block of noderefs */
}
RefBlock;
/*-------------------------------------------------------------------------*/
static NodeBlock *pFreeNBlocks = NULL; /* Nodeblocks */
static RefBlock *pFreeRBlocks = NULL; /* Refblocks */
static NodeRef *pFreeRefs = NULL; /* List of free NodeRefs */
static Node *pTree = NULL; /* Dependency tree */
static Node *pList = NULL; /* List of (tree) nodes */
/* The List is used as TODO list for the files to analyse as well as
* stack simulation for the tree traversal.
*/
/*-------------------------------------------------------------------------*/
static Node *
nodes_newnode (void)
/* Allocate a new Node.
*
* Result:
* Pointer to the new Node, or NULL on error.
*
* The memory of the Node is cleared, except for .flags which is set
* to NODE_NEW.
*/
{
Node * pNode;
if (!pFreeNBlocks || !pFreeNBlocks->iFree)
{
NodeBlock * pNewBlock;
pNewBlock = (NodeBlock *)malloc(sizeof(*pNewBlock));
if (!pNewBlock)
return NULL;
memset(pNewBlock, 0, sizeof(*pNewBlock));
pNewBlock->iFree = NBLOCKSIZE;
pNewBlock->pNext = pFreeNBlocks;
pFreeNBlocks = pNewBlock;
}
pNode = &(pFreeNBlocks->aNodes[--pFreeNBlocks->iFree]);
pNode->flags |= NODE_NEW;
pNode->iInclude = -1;
return pNode;
}
/*-------------------------------------------------------------------------*/
static NodeRef *
nodes_newref (void)
/* Allocate a new NodeRef.
*
* Result:
* Pointer to the new NodeRef, or NULL on error.
*
* The memory of the NodeRef is cleared.
*/
{
NodeRef * pRef;
if (pFreeRefs)
{
pRef = pFreeRefs;
pFreeRefs = pRef->pNext;
}
else
{
if (!pFreeRBlocks || !pFreeRBlocks->iFree)
{
RefBlock * pNewBlock;
pNewBlock = (RefBlock *)malloc(sizeof(*pNewBlock));
if (!pNewBlock)
return NULL;
pNewBlock->iFree = NBLOCKSIZE;
pNewBlock->pNext = pFreeRBlocks;
pFreeRBlocks = pNewBlock;
}
pRef = &(pFreeRBlocks->aRefs[--pFreeRBlocks->iFree]);
}
memset(pRef, 0, sizeof(*pRef));
return pRef;
}
/*-------------------------------------------------------------------------*/
Node *
nodes_findadd (const char *pName, int bAddToList)
/* Find the node associated with file *pName.
* If necessary, add the node.
*
* pName: Pointer to the (minimalized) filename of the node.
* bAddToList: If true, a newly allocated node is also added to
* the TODO list.
*
* Result:
* Pointer to the node associated with this filename, or NULL on error.
*
* If the node has been added by this call, NODE_NEW is set in its .flags,
* but it is empty otherwise.
*/
{
Node * pThis, * pPrev;
int i;
assert(pName);
if (!pTree)
{
pTree = nodes_newnode();
if (bAddToList)
{
pTree->pNext = pList;
pList = pTree;
}
return pTree;
}
pPrev = NULL;
pThis = pTree;
while(pThis)
{
i = strcmp(pThis->pName, pName);
if (!i)
return pThis;
pPrev = pThis;
if (i > 0)
pThis = pThis->pLeft;
else
pThis = pThis->pRight;
}
pThis = nodes_newnode();
if (pThis)
{
if (i > 0)
pPrev->pLeft = pThis;
else
pPrev->pRight = pThis;
if (bAddToList)
{
pThis->pNext = pList;
pList = pThis;
}
}
return pThis;
}
/*-------------------------------------------------------------------------*/
Node *
nodes_find (const char *pName)
/* Find the node associated with file *pName.
*
* pName: Pointer to the (minimalized) filename of the node.
*
* Result:
* Pointer to the node associated with this filename, or NULL on error.
*/
{
Node * pThis, * pPrev;
int i;
assert(pName);
if (!pTree)
return NULL;
pPrev = NULL;
pThis = pTree;
while(pThis)
{
i = strcmp(pThis->pName, pName);
if (!i)
return pThis;
pPrev = pThis;
if (i > 0)
pThis = pThis->pLeft;
else
pThis = pThis->pRight;
}
return NULL;
}
/*-------------------------------------------------------------------------*/
int
nodes_addsource (char *pName, int bAvoid)
/* Add a source file to the dependency tree.
*
* pName : Name of the file to add (it will be duplicated).
* bAvoid: TRUE if this is a file to be avoided.
*
* Result:
* 0 on success, non-0 on error (out of memory).
*
* The file is also added to the internal TODO list of files if it is
* a genuine source file.
*/
{
Node *pNode;
char *pBasename;
assert(pName);
pName = util_getpath(pName, &pBasename);
if (!pName)
return 1;
pNode = nodes_findadd(pName, !bAvoid);
if (!pNode)
return 1;
if (pNode->flags & NODE_NEW)
{
pNode->flags = NODE_SOURCE;
pNode->pName = pName;
pNode->pBase = pBasename;
pNode->pPath = util_getpath(pName, NULL);
if (!pNode->pPath)
return 1;
}
else
free(pName);
if (bAvoid)
pNode->flags |= NODE_AVOID;
return 0;
}
/*-------------------------------------------------------------------------*/
int
nodes_depend (Node * pChild, Node * pParent)
/* Add node pChild to the list of dependees of pParent, vice versa add
* pParent to the list of users of pName.
*
* pChild : Node of the file included by pParent.
* pParent: Node which depends on pChild.
*
* Result:
* 0 on success, non-0 on error (out of memory).
*
* The file is added to the dependee- and user-lists.
*/
{
NodeRef * pRef;
assert(pParent);
assert(pChild);
/* Add pChild to pParent->pDeps if not already there */
for ( pRef = pParent->pDeps
; pRef && pRef->pNode != pChild
; pRef = pRef->pNext
) /* SKIP */;
if (!pRef)
{
pRef = nodes_newref();
if (!pRef)
return 1;
pRef->pNode = pChild;
pRef->pNext = pParent->pDeps;
pParent->pDeps = pRef;
}
/* Add pParent to pChild->pUsers if not already there */
for ( pRef = pChild->pUsers
; pRef && pRef->pNode != pParent
; pRef = pRef->pNext
) /* SKIP */;
if (!pRef)
{
pRef = nodes_newref();
if (!pRef)
return 1;
pRef->pNode = pParent;
pRef->pNext = pChild->pUsers;
pChild->pUsers = pRef;
}
return 0;
}
/*-------------------------------------------------------------------------*/
Node *
nodes_todo (void)
/* Return the tree node of the next file to analyse.
*
* Result:
* Pointer to the node of the next file to analyse, or NULL if there is
* none.
*/
{
Node * pNode;
/* NODE_DONE should not happen, but checking it is free */
while (pList && (pList->flags & (NODE_AVOID|NODE_DONE)))
pList = pList->pNext;
if (pList)
{
pNode = pList;
pList = pList->pNext;
pNode->flags |= NODE_DONE;
}
else
pNode = NULL;
return pNode;
}
/*-------------------------------------------------------------------------*/
int
nodes_mark_select (Node *pNode)
/* Check if this node, or one of its dependency nodes has been marked
* as selected. If yes, mark pNode as well and return TRUE, otherwise
* return FALSE.
*
* This is a recursive function. We avoid loops by temporarily marking
* the node.
*/
{
int rc;
NodeRef * pRef;
assert(pNode);
if (NODES_MARKED(pNode))
return FALSE;
if (pNode->flags & NODE_ISELECT)
return TRUE;
NODES_MARK(pNode);
/* First, recurse into the dependency nodes */
rc = FALSE;
for (pRef = pNode->pDeps; pRef != NULL; pRef = pRef->pNext)
{
if (nodes_mark_select(pRef->pNode))
rc = TRUE;
}
if (rc && !(pNode->flags & NODE_SELECT))
{
pNode->flags |= NODE_ISELECT;
}
NODES_UNMARK(pNode);
return rc || (pNode->flags & (NODE_SELECT|NODE_ISELECT));
} /* nodes_mark_select() */
/*-------------------------------------------------------------------------*/
void
nodes_initwalk (void)
/* Initialise a tree traversal.
*/
{
assert(!pList);
pList = pTree;
if (pList)
{
pList->iStage = 0;
pList->pNext = NULL;
}
}
/*-------------------------------------------------------------------------*/
Node *
nodes_inorder (void)
/* Return the next Node of an inorder tree traversal.
*
* Result:
* Pointer to the next node, or NULL if traversal is complete.
*/
{
Node *pNode = NULL;
if (!pList)
return NULL;
while (pList)
{
switch (pList->iStage)
{
case 0:
pList->iStage++;
pNode = pList->pLeft;
break;
case 1:
pList->iStage++;
return pList;
break;
case 2:
pList->iStage++;
pNode = pList->pRight;
break;
case 3:
pList = pList->pNext;
pNode = NULL;
break;
default:
assert(0);
break;
}
if (pNode)
{
pNode->pNext = pList;
pList = pNode;
pNode->iStage = 0;
}
}
return NULL;
}
/*-------------------------------------------------------------------------*/
NodeRef *
nodes_deplist (Node * pNode, int bUsers, int bSelect)
/* Gather the list of dependees or users of *pNode.
*
* pNode: the Node to get the list for.
* bUsers: TRUE: gather the list of users instead of the dependees.
* bSelect: TRUE: gather only files marked as NODE_SELECT.
*
* Result:
* Pointer to the list of dependees/users, or NULL if an error occurs.
* First entry in the list is pNode itself.
*/
{
NodeRef *pDList;
NodeRef *pMark;
NodeRef *pThis;
NodeRef *pRover;
Node *pDep;
assert(pNode);
pDList = nodes_newref();
if (!pDList)
return NULL;
/* The list of dependencies is gathered in a wide search. */
pDList->pNode = pNode;
NODES_MARK(pNode);
for ( pThis = pDList, pMark = pDList
; pMark
; pMark = pMark->pNext
)
{
for ( pRover = (bUsers ? pMark->pNode->pUsers : pMark->pNode->pDeps)
; pRover
; pRover = pRover->pNext
)
{
pDep = pRover->pNode;
if (!NODES_MARKED(pDep))
{
pThis->pNext = nodes_newref();
if (!pThis->pNext)
return NULL;
pThis = pThis->pNext;
pThis->pNode = pDep;
NODES_MARK(pDep);
}
}
}
/* If bSelect is requested, remove all non-SELECT nodes from the list
* (but always keep the first one).
*/
if (bSelect)
{
pThis = pDList;
while (pThis->pNext != NULL)
{
pMark = pThis->pNext;
if (!(pMark->pNode->flags & NODE_SELECT))
{
NODES_UNMARK(pMark->pNode);
pThis->pNext = pMark->pNext;
pMark->pNext = pFreeRefs;
pFreeRefs = pMark;
}
else
pThis = pMark;
}
}
return pDList;
}
/*-------------------------------------------------------------------------*/
void
nodes_freelist (NodeRef * pDList)
/* Free a dependency list produced earlier by nodes_deplist().
*
* pDList: Base of the list to free.
*/
{
NodeRef * pThis;
while (pDList)
{
NODES_UNMARK(pDList->pNode);
pThis = pDList;
pDList = pDList->pNext;
pThis->pNext = pFreeRefs;
pFreeRefs = pThis;
}
}
/***************************************************************************/

95
src/bin/mkdepend/nodes.h Normal file
View File

@ -0,0 +1,95 @@
/* $Id: nodes.h 1.5 Wed, 01 Mar 2000 21:15:40 -0700 lars $ */
/*---------------------------------------------------------------------------
** Copyright (c) 1995-2000 by Lars Düning. All Rights Reserved.
** This file is free software. For terms of use see the file LICENSE.
**---------------------------------------------------------------------------
*/
#ifndef __NODES_H__
#define __NODES_H__ 1
struct noderef; /* forward */
/* Node structure to build the dependency tree
*/
typedef struct node
{
struct node * pLeft, * pRight; /* Tree pointers */
struct node * pNext; /* List of Files to do; stack for traversals */
char * pName;
/* Searchkey: Name of this file.
* This is the minimal full pathname with which the file can be read.
* For source files (and files to be avoided) it is identical with the name
* given on the commandline.
*/
char * pBase;
/* The filename part of the the file's pathname.
* This is a pointer into pName.
*/
char * pPath;
/* The directory part of the file's pathname.
* Relative paths are interpreted depending on the type of the file:
* source files are relative to the current working directory,
* non-source files are relative to aIncl[.iInclude].
*/
int iInclude;
/* Included non-sourcefiles: the index into aIncl[]/aSymbol[].
* A negative index denotes an absolute filename, or one relative
* to the cwd.
*/
short flags; /* misc flags */
struct noderef * pDeps; /* What this file depends on */
struct noderef * pUsers; /* Who depends on this file */
short iStage; /* Stage counter for tree traversals */
}
Node;
/* Node.flags
*/
#define NODE_MARK (1<<0) /* Generic Node marker, used e.g. in tree walks */
#define NODE_NEW (1<<1) /* Node is unused */
#define NODE_SOURCE (1<<2) /* Node is a skeleton source */
#define NODE_AVOID (1<<3) /* Node is not part of the skeleton sources */
#define NODE_NOTFND (1<<4) /* Node describes a non-existant file */
#define NODE_DONE (1<<5) /* Node has been evaluated */
#define NODE_SYSTEM (1<<6) /* File is an <>-include */
#define NODE_IGNORE (1<<7) /* Data for this node shall not be printed */
#define NODE_SELECT (1<<8) /* Marks selected include files */
#define NODE_ISELECT (1<<9) /* Marks nodes between source and selected
* include files */
/* Node marking
*/
#define NODES_MARK(node) ((node)->flags |= NODE_MARK)
#define NODES_UNMARK(node) ((node)->flags &= (short)(~NODE_MARK))
#define NODES_MARKED(node) ((node)->flags & NODE_MARK)
/* Test if the _SYSTEM flag has a specific value
*/
#define NODES_SYSTEST(node,value) ( (node)->flags & NODE_SYSTEM ? (value) : !(value) )
/* Reference structure to treenodes
*/
typedef struct noderef
{
struct noderef * pNext; /* next NodeRef */
Node * pNode; /* referenced Node */
}
NodeRef;
/* Prototypes */
extern Node * nodes_findadd (const char *, int);
extern Node * nodes_find (const char *);
extern int nodes_addsource (char *, int);
extern int nodes_depend (Node *, Node *);
extern int nodes_mark_select (Node *);
extern Node * nodes_todo (void);
extern void nodes_initwalk (void);
extern Node * nodes_inorder (void);
extern NodeRef * nodes_deplist (Node *, int, int);
extern void nodes_freelist (NodeRef *);
#endif

658
src/bin/mkdepend/reader.c Normal file
View File

@ -0,0 +1,658 @@
/* $Id: reader.c 1.9 Wed, 01 Mar 2000 22:36:57 -0700 lars $ */
/*---------------------------------------------------------------------------
** Reading of C-Sources and filter for #include statements.
** Also here are routines for the modification of Makefiles.
**
** Copyright (c) 1995-1998 by Lars Düning. All Rights Reserved.
** This files is free software. For terms of use see the file LICENSE.
**---------------------------------------------------------------------------
** Credits:
** The buffering scheme was inspired by the input module of lcc (by
** Chris Fraser & David Hanson).
**---------------------------------------------------------------------------
*/
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "reader.h"
/*-------------------------------------------------------------------------*/
struct filestate
{
int len; /* Number of bytes buffered */
char buf[1]; /* allocated to <len> bytes */
};
#define BUFSIZE 10240 /* Size of the file buffer */
static char aBuffer[BUFSIZE+1]; /* File buffer */
static int fdFile; /* Filehandle */
static int fdFile2; /* Filehandle Writer */
static char * pLimit; /* Pointer to closing sentinel in buffer */
static char * pch; /* Pointer to actual char in buffer */
static char * pIName; /* Start of include filename */
static struct filestate * pState; /* Saved state of the Makefile */
#define END_OF_BUF() (pch >= pLimit)
#define END_OF_FILE() (pLimit == aBuffer)
/*-------------------------------------------------------------------------*/
void
reader_init (void)
/* Initialize the reader.
*/
{
fdFile = -1;
fdFile2 = -1;
aBuffer[BUFSIZE] = '\n';
pLimit = aBuffer+BUFSIZE;
pch = pLimit;
pIName = NULL;
pState = NULL;
}
/*-------------------------------------------------------------------------*/
static int
fillbuffer (void)
/* Read in the next chunk from file such that incrementing pch will
* access the newly read data.
*
* Result:
* 0 on success, non-0 else (errno holds error code then).
* pch is set to the start of the new data.
*/
{
int iRead;
if (END_OF_FILE())
return 1;
if (pIName)
{
if (pch > pLimit)
pch = pLimit;
memcpy(aBuffer, pIName, (unsigned)(pLimit-pIName));
pch -= (pLimit-pIName);
}
else
pch = aBuffer;
iRead = read(fdFile, pch, (unsigned)(aBuffer+BUFSIZE-pch));
if (iRead >= 0)
{
pLimit = pch+iRead;
*pLimit = '\n';
}
return iRead < 0;
}
/*-------------------------------------------------------------------------*/
int
reader_open (const char *pName)
/* Open a file for reading.
*
* pName: Name of the file to read.
*
* Result:
* 0 on success, non-0 else (errno contains error code then).
*
* The reader is initialized to read and filter the file name *pName.
*/
{
assert(pName);
assert(fdFile < 0);
reader_init();
fdFile = open(pName, O_RDONLY);
return fdFile >= 0;
}
/*-------------------------------------------------------------------------*/
int
reader_openrw (const char *pNameR, const char *pNameW)
/* Open two makefiles for modification.
*
* pNameR: Name of the file to read, may be NULL.
* pNameW: Name of the file to read.
*
* Result:
* 0 on success, non-0 else (errno contains error code then).
*
* The reader is initialized to read the old makefile *pNameR and writing
* of new makefile *pNameW.
* If no pNameR is given, the reader is immediately initialized to
* write *pNameW.
*/
{
assert(pNameW);
assert(fdFile < 0);
assert(fdFile2 < 0);
reader_init();
fdFile2 = open(pNameW, O_WRONLY|O_CREAT|O_TRUNC, 0664);
if (fdFile2 < 0)
return 1;
if (pNameR)
{
fdFile = open(pNameR, O_RDONLY);
if (fdFile < 0)
{
close(fdFile2);
fdFile2 = -1;
}
}
else
pch = aBuffer;
return fdFile2 < 0;
}
/*-------------------------------------------------------------------------*/
int
reader_close (void)
/* Close the file currently read.
* Result:
* 0 on success, non-0 else.
* errno set to error code in case.
*/
{
int i;
i = 0;
if (fdFile >= 0)
{
i = close(fdFile);
}
fdFile = -1;
if (fdFile2 >= 0)
{
i = close(fdFile2) || i;
}
fdFile2 = -1;
if (pState)
{
free(pState);
}
pState = NULL;
return i;
}
/*-------------------------------------------------------------------------*/
int
reader_eof (void)
/* Test if the file read is at its end.
*
* Result:
* Non-0 on end of file.
*/
{
return END_OF_FILE();
}
/*-------------------------------------------------------------------------*/
const char *
reader_get (int * pType)
/* Extract the next include statement from the file being read.
*
* Result:
* Pointer to the filename extracted from the statement, or NULL on error
* or end of file.
* The memory is property of reader_get(), the pointer valid just until
* the next call to reader_get().
* <*pType> is set to 0 for an ""-include, and non-zero for an <>-include.
* <errn>o set to an error code in case.
*/
{
enum { StartOfLine, InLine, FoundHash, SkipComment, SkipLComment, FoundInclude
} eState;
/* For debugging purposes:
char *stab[]
= {
"Start "
, "InLine"
, "Found#"
, "SkipC "
, "SkipLC"
, "FoundI"
};
*/
char ch;
int iFound; /* Number of chars found of "include" */
int bDone; /* 0: still searching, 1: found include */
int bType; /* 0: ""-include, 1: <>-include */
#define GETCHAR() \
ch = *pch++; \
if (ch == '\n' && pch >= pLimit) \
{ \
if (fillbuffer()) { \
pIName = NULL; \
return NULL; \
} \
ch = *pch++; \
}
if (pIName)
eState = InLine;
else
eState = StartOfLine;
pIName = NULL;
iFound = 0;
bType = 0;
bDone = 0;
while (!bDone)
{
/* Get the next interesting non-linefeed character */
do {
GETCHAR()
if (ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f')
{
eState = StartOfLine;
pIName = NULL;
}
else
break;
} while (1);
switch(eState)
{
case StartOfLine:
switch (ch)
{
case '#':
eState = FoundHash;
iFound = 0;
break;
case '/':
GETCHAR()
if (ch == '/')
eState = SkipLComment;
else if (ch == '*')
eState = SkipComment;
else
eState = InLine;
break;
case ' ': case '\t':
/* still: eState = StartOfLine; */
break;
default:
eState = InLine;
break;
}
break;
case InLine:
switch (ch)
{
case '/':
GETCHAR()
if (ch == '/')
eState = SkipLComment;
else if (ch == '*')
eState = SkipComment;
else
eState = InLine;
break;
case '\\':
GETCHAR()
/* still: eState = InLine; */
break;
default:
/* still: eState = InLine; */
break;
}
break;
case FoundHash:
switch(ch)
{
case ' ': case '\t':
if (iFound)
{
eState = InLine;
iFound = 0;
}
/* else still: eState = FoundHash */
break;
case 'i': case 'n': case 'c': case 'l':
case 'u': case 'd': case 'e':
if ("include"[iFound] != ch)
{
eState = InLine;
iFound = 0;
}
else if (ch == 'e')
{
eState = FoundInclude;
pIName = NULL;
}
else
iFound++;
break;
default:
eState = InLine;
}
break;
case FoundInclude:
switch(ch)
{
case ' ': case '\t':
/* still: eState = FoundInclude */
break;
case '<':
if (!pIName)
{
pIName = pch;
bType = 1;
}
else
eState = InLine;
break;
case '>':
if (!pIName)
{
eState = InLine;
}
else if (bType)
{
*(pch-1) = '\0';
if (pch-1 == pIName)
pIName = NULL;
else
bDone = 1;
eState = InLine;
}
break;
case '"':
if (!pIName)
{
pIName = pch;
bType = 0;
}
else if (!bType)
{
*(pch-1) = '\0';
if (pch-1 == pIName)
pIName = NULL;
else
bDone = 1;
eState = InLine;
}
break;
default:
if (!pIName)
eState = InLine;
break;
}
break;
case SkipComment:
case SkipLComment:
break;
} /* switch (eState) */
/* Skip comments immediately */
if (eState == SkipComment)
{
while(1) {
do {
GETCHAR()
} while (ch != '*');
GETCHAR()
if (ch == '/')
break;
}
eState = StartOfLine;
}
else if (eState == SkipLComment)
{
do {
GETCHAR()
} while (ch != '\n' && ch != '\r' && ch != '\v' && ch != '\f');
eState = StartOfLine;
}
} /* while(!bDone) */
*pType = bType;
return pIName;
#undef GETCHAR
}
/*-------------------------------------------------------------------------*/
int
reader_writeflush (void)
/* Write out the buffer to the written makefile.
* Return 0 on success, non-0 else (errno holds the error code then).
*/
{
if (pch > aBuffer
&& write(fdFile2, aBuffer, (unsigned)(pch-aBuffer)) != pch-aBuffer)
return 1;
pch = aBuffer;
return 0;
}
/*-------------------------------------------------------------------------*/
int
reader_writen (const char *pText, size_t len)
/* Append the first <len> characters of <pText> to the written file.
* Return 0 on success, non-0 else (errno holds the error code then)
*/
{
assert(pText);
assert(fdFile2 >= 0);
if (pLimit-pch < (signed)len && reader_writeflush())
return 1;
memcpy(pch, pText, len);
pch += len;
return 0;
}
/*-------------------------------------------------------------------------*/
int
reader_write (const char *pText)
/* Append <pText> to the written file.
* Return 0 on success, non-0 else (errno holds the error code then)
*/
{
return reader_writen(pText, strlen(pText));
}
/*-------------------------------------------------------------------------*/
int
reader_copymake (const char * pTagline)
/* Copy the file from fdFile to fdFile2 up to including the tagline.
* If the tagline is not found, it is appended.
* The tagline MUST end in a newline character!
* Return 0 on success, non-0 on error (errno holds the error code then).
*/
{
size_t len;
int count; /* Next charactor to compare in pTagline, or -1 if to skip
* up to the next Newline */
char ch;
assert(pTagline);
assert(fdFile2);
len = strlen(pTagline);
assert(len < 120);
/* Simplest case: no old makefile to copy */
if (fdFile < 0)
{
strcpy(aBuffer, pTagline);
pch = aBuffer+len;
return 0;
}
if (fillbuffer())
return 1;
count = 0;
while (!END_OF_FILE() && count < (signed)len)
{
if (END_OF_BUF())
{
if (write(fdFile2, aBuffer, (unsigned)(pch-aBuffer)) != pch-aBuffer)
return 1;
if (fillbuffer())
return 1;
if (END_OF_FILE())
break;
}
ch = *pch;
if (count < 0)
{
if (ch == '\n')
count = 0;
}
else
{
if (ch == pTagline[count])
count++;
else if (ch == '\n')
count = 0;
else
count = -1;
}
pch++;
}
/* Remember the state of the Makefile read */
if (!END_OF_FILE())
{
pState = (struct filestate *) malloc(sizeof(*pState)+(pLimit-pch));
if (pState)
{
pState->len = pLimit-pch;
memcpy(pState->buf, pch, (size_t)pState->len);
}
}
/* Switch to write mode */
pLimit = aBuffer+BUFSIZE;
/* Append a newline if missing */
if (count < 0 && reader_writen("\n", 1))
return 1;
/* Put the Tagline into the buffer if necessary */
if (count < (signed)len && reader_writen(pTagline, (size_t)len))
return 1;
return 0;
}
/*-------------------------------------------------------------------------*/
int
reader_copymake2 (const char * pTagline)
/* Copy the remainder from fdFile to fdFile2 starting with the tagline.
* The tagline MUST end in a newline character!
* Return 0 on success, non-0 on error (errno holds the error code then).
*/
{
size_t len;
int count; /* Next charactor to compare in pTagline, or -1 if to skip
* up to the next Newline */
char ch;
assert(pTagline);
assert(fdFile);
assert(fdFile2);
len = strlen(pTagline);
assert(len < 120);
/* Append the tagline to the file written */
if (reader_write(pTagline) || reader_writeflush())
return 1;
/* Easiest case: nothing to left copy */
if (!pState)
return 0;
/* Restore the aBuffer to the point where the reading stopped */
pLimit = aBuffer+BUFSIZE;
pch = pLimit-pState->len;
memcpy(pch, pState->buf, (size_t)pState->len);
free(pState);
pState = NULL;
pIName = NULL;
/* Fill up the buffer */
if (END_OF_BUF() && fillbuffer())
return 1;
/* Skip the Makefile read until the tagline has been found */
count = 0;
while (!END_OF_FILE() && count < (signed)len)
{
if (END_OF_BUF())
{
if (fillbuffer())
return 1;
if (END_OF_FILE())
break;
}
ch = *pch;
if (count < 0)
{
if (ch == '\n')
count = 0;
}
else
{
if (ch == pTagline[count])
count++;
else if (ch == '\n')
count = 0;
else
count = -1;
}
pch++;
}
/* Copy the remainder of the Makefile */
do
{
if (!END_OF_BUF()
&& write(fdFile2, pch, (unsigned)(pLimit-pch)) != pLimit-pch)
return 1;
if (!END_OF_FILE() && fillbuffer())
return 1;
}
while (!END_OF_FILE());
return 0;
}
/***************************************************************************/

24
src/bin/mkdepend/reader.h Normal file
View File

@ -0,0 +1,24 @@
/* $Id: reader.h 1.4 Wed, 01 Mar 2000 21:15:40 -0700 lars $ */
/*---------------------------------------------------------------------------
** Copyright (c) 1995-1998 by Lars Düning. All Rights Reserved.
** This file is free software. For terms of use see the file LICENSE.
**---------------------------------------------------------------------------
*/
#ifndef __READER_H__
#define __READER_H__ 1
extern void reader_init (void);
extern int reader_open (const char *);
extern int reader_openrw (const char *, const char *);
extern int reader_close (void);
extern int reader_eof (void);
extern const char * reader_get (int *);
extern int reader_writeflush (void);
extern int reader_writen (const char *, size_t);
extern int reader_write (const char *);
extern int reader_copymake (const char *);
extern int reader_copymake2 (const char *);
#endif

146
src/bin/mkdepend/util.c Normal file
View File

@ -0,0 +1,146 @@
/* $Id: util.c 1.2 Wed, 01 Mar 2000 21:23:27 -0700 lars $ */
/*---------------------------------------------------------------------------
* Useful functions.
*
* Copyright (c) 1999 by Lars Düning. All Rights Reserved.
* This file is free software. For terms of use see the file LICENSE.
*---------------------------------------------------------------------------
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
/*-------------------------------------------------------------------------*/
char *
util_getpath (const char * pDirtyName, char ** ppBasename)
/* Take the <pDirtyName> and eliminate as many '.' and '..' from it
* as possible. Return a freshly allocated copy of the cleaned up path.
* If ppBasename is NULL, the returned name will only contain the
* directory parts, the filename will be dropped. If ppBasename is not
* NULL, the returned name will contain the filename, and *ppBasename
* will be set to point to its first character.
*
* Return NULL when out of memory.
*/
{
char * pPath; /* The newly created pathname */
char * pStart; /* The first non-'/'-character of pPath */
char * pSrc, * pDest; /* Working pointers */
size_t oFilename; /* Offset of filename in pDirtyName */
assert(pDirtyName);
pPath = strdup(pDirtyName);
if (!pPath)
return NULL;
pStart = ('/' == *pPath) ? pPath+1 : pPath;
/* First scan: find the first character of the filename
* and end the string there, leaving just the directory path.
* But remember the offset of the filename.
*/
pDest = pStart; /* First character after last '/' found */
pSrc = pStart; /* Rover */
while ('\0' != *pSrc)
{
if ('/' == *pSrc++)
pDest = pSrc;
}
*pDest = '\0';
oFilename = (unsigned)(pDest - pPath);
/* pPath now ends in a '/', or *pStart is a '\0' */
/* Second scan: visit all directory parts and eliminate '.'
* and '..' where possible.
*/
pDest = pStart; /* First character after last valid '/' */
pSrc = pStart;
/* Skip initial '.' entries */
while ('.' == *pSrc)
{
if ('/' == pSrc[1])
{
pSrc += 2;
}
else
break;
}
while ('\0' != *pSrc)
{
char ch;
/* Copy forward until the next '/' */
do
{
ch = *pSrc++;
*pDest++ = ch;
} while ('/' != ch);
/* If a '.' follows, it might be a '.' or '..' entry */
while ('.' == *pSrc)
{
pSrc++;
if ('/' == *pSrc)
{
/* Simply skip the '.' entry */
pSrc++;
}
else if ('.' == pSrc[0] && '/' == pSrc[1] && pDest != pStart)
{
/* For a '..' entry, move pDest back one directory unless
* it is at the start of the string
*/
char * pLastDest;
for ( pLastDest = pDest-1
; pLastDest != pStart && '/' != pLastDest[-1]
; pLastDest--) /* SKIP */;
/* Special case: if the part just unrolled is '..' itself,
* don't do the unrolling and instead break the loop.
*/
if (pLastDest + 3 == pDest && pLastDest[0] == '.' && pLastDest[1] == '.')
{
*pDest++ = '.';
break;
}
else
{
pSrc += 2;
pDest = pLastDest;
}
}
else
{
/* Its not a '.' or handleable '..' entry */
*pDest++ = '.';
break;
}
}
}
*pDest = '\0';
/* If the caller wants to have the filename too, append it to
* the clean directory.
*/
if (ppBasename)
{
strcpy(pDest, pDirtyName+oFilename);
*ppBasename = pDest;
}
return pPath;
}
/***************************************************************************/

14
src/bin/mkdepend/util.h Normal file
View File

@ -0,0 +1,14 @@
/* $Id: util.h 1.1 Tue, 02 Feb 1999 17:57:55 -0700 lars $ */
/*---------------------------------------------------------------------------
* Copyright (c) 1999 by Lars Düning. All Rights Reserved.
* This file is free software. For terms of use see the file LICENSE.
*---------------------------------------------------------------------------
*/
#ifndef __UTIL_H__
#define __UTIL_H__ 1
extern char * util_getpath(const char *, char **);
#endif

View File

@ -0,0 +1,38 @@
/* $Id: version.h 1.2 Sat, 24 Oct 1998 19:54:13 -0600 lars $ */
/*---------------------------------------------------------------------------
* Version information for MkDepend.
*
* Copyright (c) 1998 by Lars Düning. All Rights Reserved.
* This file is free software. For terms of use see the file LICENSE.
*---------------------------------------------------------------------------
* This macros are exported:
*
* VERSION: a string of the form "x.y" or "x.y.z", with z being >= 2.
* RELEASEDATE: a string with date and time when the current version was
* checked in.
* PRCS_LEVEL: the internal minor version of MkDepend, used for <z>
* in VERSION when the value is >= 2.
*
* The values are created by PRCS.
*---------------------------------------------------------------------------
*/
#ifndef __VERSION_H__
#define __VERSION_H__
/* $Format: "#define RELEASE_DATE \"$ReleaseDate$\""$ */
#define RELEASE_DATE "Thu, 19 Mar 2009 11:20:00 -0100"
/* $Format: "#define PRCS_LEVEL $ProjectMinorVersion$"$ */
#define PRCS_LEVEL 1
#if PRCS_LEVEL > 1
/* $Format: "#define VERSION \"$ReleaseVersion$.$ProjectMinorVersion$\""$ */
#define VERSION "1.7.1"
#else
/* $Format: "#define VERSION \"$ReleaseVersion$\""$ */
#define VERSION "1.7"
#endif
#endif /* __VERSION_H__ */