diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/Makefile | 12 | ||||
-rw-r--r-- | examples/Makefile.http.in | 12 | ||||
-rw-r--r-- | examples/Makefile.telnet.in | 12 | ||||
-rw-r--r-- | examples/OCamlMakefile | 1154 | ||||
-rw-r--r-- | examples/http.ml | 688 | ||||
-rw-r--r-- | examples/telnet.ml | 181 |
6 files changed, 2059 insertions, 0 deletions
diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..2b9d33d --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,12 @@ +# OCaml-Lastfm examples. +# +# Copyright 2007 by the Savonet team. +# +# $Id: Makefile 4694 2007-10-23 23:33:11Z smimram $ + +all clean: + $(MAKE) -f Makefile.telnet $@ + $(MAKE) -f Makefile.http $@ + +distclean: clean + rm -rf autom4te.cache config.log config.status autom4te.cache diff --git a/examples/Makefile.http.in b/examples/Makefile.http.in new file mode 100644 index 0000000..d560b96 --- /dev/null +++ b/examples/Makefile.http.in @@ -0,0 +1,12 @@ +SOURCES = http.ml +RESULT = http +INCDIRS = ../src @ALL_INC@ +OCAMLC = @OCAMLC@ -thread +OCAMLOPT = @OCAMLOPT@ -thread +LIBS = @all_requires@ duppy +PP = camlp4o -I ../src pa_duppy.cmo +export PP + +all: nc + +-include OCamlMakefile diff --git a/examples/Makefile.telnet.in b/examples/Makefile.telnet.in new file mode 100644 index 0000000..5cc1869 --- /dev/null +++ b/examples/Makefile.telnet.in @@ -0,0 +1,12 @@ +SOURCES = telnet.ml +RESULT = telnet +INCDIRS = ../src @ALL_INC@ +OCAMLC = @OCAMLC@ -thread +OCAMLOPT = @OCAMLOPT@ -thread +LIBS = @all_requires@ duppy +PP = camlp4o -I ../src pa_duppy.cmo +export PP + +all: nc + +-include OCamlMakefile diff --git a/examples/OCamlMakefile b/examples/OCamlMakefile new file mode 100644 index 0000000..6f62c91 --- /dev/null +++ b/examples/OCamlMakefile @@ -0,0 +1,1154 @@ +########################################################################### +# OCamlMakefile +# Copyright (C) 1999-2004 Markus Mottl +# +# For updates see: +# http://www.ocaml.info/home/ocaml_sources.html +# +# $Id: OCamlMakefile,v 1.72 2005/12/09 15:30:50 mottl Exp $ +# +########################################################################### + +# Modified by damien for .glade.ml compilation + +# Set these variables to the names of the sources to be processed and +# the result variable. Order matters during linkage! + +ifndef SOURCES + SOURCES := foo.ml +endif +export SOURCES + +ifndef RES_CLIB_SUF + RES_CLIB_SUF := _stubs +endif +export RES_CLIB_SUF + +ifndef RESULT + RESULT := foo +endif +export RESULT + +export LIB_PACK_NAME + +ifndef DOC_FILES + DOC_FILES := $(filter %.mli, $(SOURCES)) +endif +export DOC_FILES + +export BCSUFFIX +export NCSUFFIX + +ifndef TOPSUFFIX + TOPSUFFIX := .top +endif +export TOPSUFFIX + +# Eventually set include- and library-paths, libraries to link, +# additional compilation-, link- and ocamlyacc-flags +# Path- and library information needs not be written with "-I" and such... +# Define THREADS if you need it, otherwise leave it unset (same for +# USE_CAMLP4)! + +export THREADS +export VMTHREADS +export ANNOTATE +export USE_CAMLP4 + +export INCDIRS +export LIBDIRS +export EXTLIBDIRS +export RESULTDEPS +export OCAML_DEFAULT_DIRS + +export LIBS +export CLIBS + +export OCAMLFLAGS +export OCAMLNCFLAGS +export OCAMLBCFLAGS + +export OCAMLLDFLAGS +export OCAMLNLDFLAGS +export OCAMLBLDFLAGS + +ifndef OCAMLCPFLAGS + OCAMLCPFLAGS := a +endif + +export OCAMLCPFLAGS + +export PPFLAGS + +export YFLAGS +export IDLFLAGS + +export OCAMLDOCFLAGS + +export OCAMLFIND_INSTFLAGS + +export DVIPSFLAGS + +export STATIC + +# Add a list of optional trash files that should be deleted by "make clean" +export TRASH + +#################### variables depending on your OCaml-installation + +ifdef MINGW + export MINGW + WIN32 := 1 + CFLAGS_WIN32 := -mno-cygwin +endif +ifdef MSVC + export MSVC + WIN32 := 1 + ifndef STATIC + CPPFLAGS_WIN32 := -DCAML_DLL + endif + CFLAGS_WIN32 += -nologo + EXT_OBJ := obj + EXT_LIB := lib + ifeq ($(CC),gcc) + # work around GNU Make default value + ifdef THREADS + CC := cl -MT + else + CC := cl + endif + endif + ifeq ($(CXX),g++) + # work around GNU Make default value + CXX := $(CC) + endif + CFLAG_O := -Fo +endif +ifdef WIN32 + EXT_CXX := cpp + EXE := .exe +endif + +ifndef EXT_OBJ + EXT_OBJ := o +endif +ifndef EXT_LIB + EXT_LIB := a +endif +ifndef EXT_CXX + EXT_CXX := cc +endif +ifndef EXE + EXE := # empty +endif +ifndef CFLAG_O + CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)! +endif + +export CC +export CXX +export CFLAGS +export CXXFLAGS +export LDFLAGS +export CPPFLAGS + +ifndef RPATH_FLAG + RPATH_FLAG := -R +endif +export RPATH_FLAG + +ifndef MSVC +ifndef PIC_CFLAGS + PIC_CFLAGS := -fPIC +endif +ifndef PIC_CPPFLAGS + PIC_CPPFLAGS := -DPIC +endif +endif + +export PIC_CFLAGS +export PIC_CPPFLAGS + +BCRESULT := $(addsuffix $(BCSUFFIX), $(RESULT)) +NCRESULT := $(addsuffix $(NCSUFFIX), $(RESULT)) +TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT)) + +ifndef OCAMLFIND + OCAMLFIND := ocamlfind +endif +export OCAMLFIND + +ifndef OCAMLC + OCAMLC := ocamlc +endif +export OCAMLC + +ifndef OCAMLOPT + OCAMLOPT := ocamlopt +endif +export OCAMLOPT + +ifndef OCAMLMKTOP + OCAMLMKTOP := ocamlmktop +endif +export OCAMLMKTOP + +ifndef OCAMLCP + OCAMLCP := ocamlcp +endif +export OCAMLCP + +ifndef OCAMLDEP + OCAMLDEP := ocamldep +endif +export OCAMLDEP + +ifndef OCAMLLEX + OCAMLLEX := ocamllex +endif +export OCAMLLEX + +ifndef OCAMLYACC + OCAMLYACC := ocamlyacc +endif +export OCAMLYACC + +ifndef OCAMLMKLIB + OCAMLMKLIB := ocamlmklib +endif +export OCAMLMKLIB + +ifndef OCAML_GLADECC + OCAML_GLADECC := lablgladecc2 +endif +export OCAML_GLADECC + +ifndef OCAML_GLADECC_FLAGS + OCAML_GLADECC_FLAGS := +endif +export OCAML_GLADECC_FLAGS + +ifndef CAMELEON_REPORT + CAMELEON_REPORT := report +endif +export CAMELEON_REPORT + +ifndef CAMELEON_REPORT_FLAGS + CAMELEON_REPORT_FLAGS := +endif +export CAMELEON_REPORT_FLAGS + +ifndef CAMELEON_ZOGGY + CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo +endif +export CAMELEON_ZOGGY + +ifndef CAMELEON_ZOGGY_FLAGS + CAMELEON_ZOGGY_FLAGS := +endif +export CAMELEON_ZOGGY_FLAGS + +ifndef OXRIDL + OXRIDL := oxridl +endif +export OXRIDL + +ifndef CAMLIDL + CAMLIDL := camlidl +endif +export CAMLIDL + +ifndef CAMLIDLDLL + CAMLIDLDLL := camlidldll +endif +export CAMLIDLDLL + +ifndef NOIDLHEADER + MAYBE_IDL_HEADER := -header +endif +export NOIDLHEADER + +export NO_CUSTOM + +ifndef CAMLP4 + CAMLP4 := camlp4 +endif +export CAMLP4 + +ifndef REAL_OCAMLFIND + ifdef PACKS + ifndef CREATE_LIB + ifdef THREADS + PACKS += threads + endif + endif + empty := + space := $(empty) $(empty) + comma := , + ifdef PREDS + PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS)) + PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS)) + OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES) + # OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES) + OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) + OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) + else + OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS)) + OCAML_DEP_PACKAGES := + endif + OCAML_FIND_LINKPKG := -linkpkg + REAL_OCAMLFIND := $(OCAMLFIND) + endif +endif + +export OCAML_FIND_PACKAGES +export OCAML_DEP_PACKAGES +export OCAML_FIND_LINKPKG +export REAL_OCAMLFIND + +ifndef OCAMLDOC + OCAMLDOC := ocamldoc +endif +export OCAMLDOC + +ifndef LATEX + LATEX := latex +endif +export LATEX + +ifndef DVIPS + DVIPS := dvips +endif +export DVIPS + +ifndef PS2PDF + PS2PDF := ps2pdf +endif +export PS2PDF + +ifndef OCAMLMAKEFILE + OCAMLMAKEFILE := OCamlMakefile +endif +export OCAMLMAKEFILE + +ifndef OCAMLLIBPATH + OCAMLLIBPATH := \ + $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/lib/ocaml) +endif +export OCAMLLIBPATH + +ifndef OCAML_LIB_INSTALL + OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib +endif +export OCAML_LIB_INSTALL + +########################################################################### + +#################### change following sections only if +#################### you know what you are doing! + +# delete target files when a build command fails +.PHONY: .DELETE_ON_ERROR +.DELETE_ON_ERROR: + +# for pedants using "--warn-undefined-variables" +export MAYBE_IDL +export REAL_RESULT +export CAMLIDLFLAGS +export THREAD_FLAG +export RES_CLIB +export MAKEDLL +export ANNOT_FLAG +export C_OXRIDL +export SUBPROJS +export CFLAGS_WIN32 +export CPPFLAGS_WIN32 + +INCFLAGS := + +SHELL := /bin/sh + +MLDEPDIR := ._d +BCDIDIR := ._bcdi +NCDIDIR := ._ncdi + +FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.oxridl %.c %.$(EXT_CXX) %.rep %.zog %.glade + +FILTERED := $(filter $(FILTER_EXTNS), $(SOURCES)) +SOURCE_DIRS := $(filter-out ./, $(sort $(dir $(FILTERED)))) + +FILTERED_REP := $(filter %.rep, $(FILTERED)) +DEP_REP := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d) +AUTO_REP := $(FILTERED_REP:.rep=.ml) + +FILTERED_ZOG := $(filter %.zog, $(FILTERED)) +DEP_ZOG := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d) +AUTO_ZOG := $(FILTERED_ZOG:.zog=.ml) + +FILTERED_GLADE := $(filter %.glade, $(FILTERED)) +DEP_GLADE := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d) +AUTO_GLADE := $(FILTERED_GLADE:.glade=.ml) + +FILTERED_ML := $(filter %.ml, $(FILTERED)) +DEP_ML := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d) + +FILTERED_MLI := $(filter %.mli, $(FILTERED)) +DEP_MLI := $(FILTERED_MLI:.mli=.di) + +FILTERED_MLL := $(filter %.mll, $(FILTERED)) +DEP_MLL := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d) +AUTO_MLL := $(FILTERED_MLL:.mll=.ml) + +FILTERED_MLY := $(filter %.mly, $(FILTERED)) +DEP_MLY := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di) +AUTO_MLY := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml) + +FILTERED_IDL := $(filter %.idl, $(FILTERED)) +DEP_IDL := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di) +C_IDL := $(FILTERED_IDL:%.idl=%_stubs.c) +ifndef NOIDLHEADER + C_IDL += $(FILTERED_IDL:.idl=.h) +endif +OBJ_C_IDL := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ)) +AUTO_IDL := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL) + +FILTERED_OXRIDL := $(filter %.oxridl, $(FILTERED)) +DEP_OXRIDL := $(FILTERED_OXRIDL:%.oxridl=$(MLDEPDIR)/%.d) $(FILTERED_OXRIDL:.oxridl=.di) +AUTO_OXRIDL := $(FILTERED_OXRIDL:.oxridl=.mli) $(FILTERED_OXRIDL:.oxridl=.ml) $(C_OXRIDL) + +FILTERED_C_CXX := $(filter %.c %.$(EXT_CXX), $(FILTERED)) +OBJ_C_CXX := $(FILTERED_C_CXX:.c=.$(EXT_OBJ)) +OBJ_C_CXX := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ)) + +PRE_TARGETS += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_OXRIDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE) + +ALL_DEPS := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_OXRIDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE) + +MLDEPS := $(filter %.d, $(ALL_DEPS)) +MLIDEPS := $(filter %.di, $(ALL_DEPS)) +BCDEPIS := $(MLIDEPS:%.di=$(BCDIDIR)/%.di) +NCDEPIS := $(MLIDEPS:%.di=$(NCDIDIR)/%.di) + +ALLML := $(filter %.mli %.ml %.mll %.mly %.idl %.oxridl %.rep %.zog %.glade, $(FILTERED)) + +IMPLO_INTF := $(ALLML:%.mli=%.mli.__) +IMPLO_INTF := $(foreach file, $(IMPLO_INTF), \ + $(basename $(file)).cmi $(basename $(file)).cmo) +IMPLO_INTF := $(filter-out %.mli.cmo, $(IMPLO_INTF)) +IMPLO_INTF := $(IMPLO_INTF:%.mli.cmi=%.cmi) + +IMPLX_INTF := $(IMPLO_INTF:.cmo=.cmx) + +INTF := $(filter %.cmi, $(IMPLO_INTF)) +IMPL_CMO := $(filter %.cmo, $(IMPLO_INTF)) +IMPL_CMX := $(IMPL_CMO:.cmo=.cmx) +IMPL_ASM := $(IMPL_CMO:.cmo=.asm) +IMPL_S := $(IMPL_CMO:.cmo=.s) + +OBJ_LINK := $(OBJ_C_IDL) $(OBJ_C_CXX) +OBJ_FILES := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK) + +EXECS := $(addsuffix $(EXE), \ + $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT))) +ifdef WIN32 + EXECS += $(BCRESULT).dll $(NCRESULT).dll +endif + +CLIB_BASE := $(RESULT)$(RES_CLIB_SUF) +ifneq ($(strip $(OBJ_LINK)),) + RES_CLIB := lib$(CLIB_BASE).$(EXT_LIB) +endif + +ifdef WIN32 +DLLSONAME := $(CLIB_BASE).dll +else +DLLSONAME := dll$(CLIB_BASE).so +endif + +NONEXECS := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \ + $(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \ + $(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmo \ + $(NCRESULT).cmi $(NCRESULT).cmx $(NCRESULT).o \ + $(RES_CLIB) $(IMPL_CMO:.cmo=.annot) \ + $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(LIB_PACK_NAME).cmx $(LIB_PACK_NAME).o + +ifndef STATIC + NONEXECS += $(DLLSONAME) +endif + +ifndef LIBINSTALL_FILES + LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \ + $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB) + ifndef STATIC + ifneq ($(strip $(OBJ_LINK)),) + LIBINSTALL_FILES += $(DLLSONAME) + endif + endif +endif + +export LIBINSTALL_FILES + +ifdef WIN32 + # some extra stuff is created while linking DLLs + NONEXECS += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp $(CLIB_BASE).exp $(CLIB_BASE).lib +endif + +TARGETS := $(EXECS) $(NONEXECS) + +# If there are IDL-files +ifneq ($(strip $(FILTERED_IDL)),) + MAYBE_IDL := -cclib -lcamlidl +endif + +ifdef USE_CAMLP4 + CAMLP4PATH := \ + $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/lib/camlp4) + INCFLAGS := -I $(CAMLP4PATH) + CINCFLAGS := -I$(CAMLP4PATH) +endif + +DINCFLAGS := $(INCFLAGS) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %) +INCFLAGS := $(DINCFLAGS) $(INCDIRS:%=-I %) +CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%) + +ifndef MSVC +CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \ + $(EXTLIBDIRS:%=-L%) $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%) \ + $(OCAML_DEFAULT_DIRS:%=-L%) +endif + +ifndef PROFILING + INTF_OCAMLC := $(OCAMLC) +else + ifndef THREADS + INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS) + else + # OCaml does not support profiling byte code + # with threads (yet), therefore we force an error. + ifndef REAL_OCAMLC + $(error Profiling of multithreaded byte code not yet supported by OCaml) + endif + INTF_OCAMLC := $(OCAMLC) + endif +endif + +ifndef MSVC +COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \ + $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \ + $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%) \ + $(OCAML_DEFAULT_DIRS:%=-ccopt -L%) +else +COMMON_LDFLAGS := -ccopt "/link -NODEFAULTLIB:LIBC $(LDFLAGS:%=%) $(SOURCE_DIRS:%=-LIBPATH:%) \ + $(LIBDIRS:%=-LIBPATH:%) $(EXTLIBDIRS:%=-LIBPATH:%) \ + $(OCAML_DEFAULT_DIRS:%=-LIBPATH:%) " +endif + +CLIBS_OPTS := $(CLIBS:%=-cclib -l%) +ifdef MSVC + ifndef STATIC + # MSVC libraries do not have 'lib' prefix + CLIBS_OPTS := $(CLIBS:%=-cclib %.lib) + endif +endif + +ifneq ($(strip $(OBJ_LINK)),) + ifdef CREATE_LIB + OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL) + else + OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL) + endif +else + OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL) +endif + +# If we have to make byte-code +ifndef REAL_OCAMLC + BYTE_OCAML := y + + # EXTRADEPS is added dependencies we have to insert for all + # executable files we generate. Ideally it should be all of the + # libraries we use, but it's hard to find the ones that get searched on + # the path since I don't know the paths built into the compiler, so + # just include the ones with slashes in their names. + EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) + SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS) + + REAL_OCAMLC := $(INTF_OCAMLC) + + REAL_IMPL := $(IMPL_CMO) + REAL_IMPL_INTF := $(IMPLO_INTF) + IMPL_SUF := .cmo + + DEPFLAGS := + MAKE_DEPS := $(MLDEPS) $(BCDEPIS) + + ifdef CREATE_LIB + override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) + override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) + ifndef STATIC + ifneq ($(strip $(OBJ_LINK)),) + MAKEDLL := $(DLLSONAME) + ALL_LDFLAGS := -dllib $(DLLSONAME) + endif + endif + endif + + ifndef NO_CUSTOM + ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS))" "" + ALL_LDFLAGS += -custom + endif + endif + + ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \ + $(COMMON_LDFLAGS) $(LIBS:%=%.cma) + CAMLIDLDLLFLAGS := + + ifdef THREADS + ifdef VMTHREADS + THREAD_FLAG := -vmthread + else + THREAD_FLAG := -thread + endif + ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) + ifndef CREATE_LIB + ifndef REAL_OCAMLFIND + ALL_LDFLAGS := unix.cma threads.cma $(ALL_LDFLAGS) + endif + endif + endif + +# we have to make native-code +else + EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) + ifndef PROFILING + SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS) + PLDFLAGS := + else + SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS) + PLDFLAGS := -p + endif + + REAL_IMPL := $(IMPL_CMX) + REAL_IMPL_INTF := $(IMPLX_INTF) + IMPL_SUF := .cmx + + override CPPFLAGS := -DNATIVE_CODE $(CPPFLAGS) + + DEPFLAGS := -native + MAKE_DEPS := $(MLDEPS) $(NCDEPIS) + + ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \ + $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS) + CAMLIDLDLLFLAGS := -opt + + ifndef CREATE_LIB + ALL_LDFLAGS += $(LIBS:%=%.cmxa) + else + override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) + override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) + endif + + ifdef THREADS + THREAD_FLAG := -thread + ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) + ifndef CREATE_LIB + ifndef REAL_OCAMLFIND + ALL_LDFLAGS := unix.cmxa threads.cmxa $(ALL_LDFLAGS) + endif + endif + endif +endif + +export MAKE_DEPS + +ifdef ANNOTATE + ANNOT_FLAG := -dtypes +else +endif + +ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \ + $(INCFLAGS) $(SPECIAL_OCAMLFLAGS) + +ifdef make_deps + -include $(MAKE_DEPS) + PRE_TARGETS := +endif + +########################################################################### +# USER RULES + +# Call "OCamlMakefile QUIET=" to get rid of all of the @'s. +QUIET=@ + +# generates byte-code (default) +byte-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ + REAL_RESULT="$(BCRESULT)" make_deps=yes +bc: byte-code + +byte-code-nolink: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ + REAL_RESULT="$(BCRESULT)" make_deps=yes +bcnl: byte-code-nolink + +top: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \ + REAL_RESULT="$(BCRESULT)" make_deps=yes + +# generates native-code + +native-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + make_deps=yes +nc: native-code + +native-code-nolink: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + make_deps=yes +ncnl: native-code-nolink + +# generates byte-code libraries +byte-code-library: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(BCRESULT).cma \ + REAL_RESULT="$(BCRESULT)" \ + CREATE_LIB=yes \ + make_deps=yes +bcl: byte-code-library + +# generates native-code libraries +native-code-library: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(NCRESULT).cmxa \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + CREATE_LIB=yes \ + make_deps=yes +ncl: native-code-library + +ifdef WIN32 +# generates byte-code dll +byte-code-dll: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(BCRESULT).dll \ + REAL_RESULT="$(BCRESULT)" \ + make_deps=yes +bcd: byte-code-dll + +# generates native-code dll +native-code-dll: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(NCRESULT).dll \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + make_deps=yes +ncd: native-code-dll +endif + +# generates byte-code with debugging information +debug-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ + REAL_RESULT="$(BCRESULT)" make_deps=yes \ + OCAMLFLAGS="-g $(OCAMLFLAGS)" \ + OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" +dc: debug-code + +debug-code-nolink: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ + REAL_RESULT="$(BCRESULT)" make_deps=yes \ + OCAMLFLAGS="-g $(OCAMLFLAGS)" \ + OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" +dcnl: debug-code-nolink + +# generates byte-code libraries with debugging information +debug-code-library: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(BCRESULT).cma \ + REAL_RESULT="$(BCRESULT)" make_deps=yes \ + CREATE_LIB=yes \ + OCAMLFLAGS="-g $(OCAMLFLAGS)" \ + OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" +dcl: debug-code-library + +# generates byte-code for profiling +profiling-byte-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ + REAL_RESULT="$(BCRESULT)" PROFILING="y" \ + make_deps=yes +pbc: profiling-byte-code + +# generates native-code + +profiling-native-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + PROFILING="y" \ + make_deps=yes +pnc: profiling-native-code + +# generates byte-code libraries +profiling-byte-code-library: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(BCRESULT).cma \ + REAL_RESULT="$(BCRESULT)" PROFILING="y" \ + CREATE_LIB=yes \ + make_deps=yes +pbcl: profiling-byte-code-library + +# generates native-code libraries +profiling-native-code-library: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(NCRESULT).cmxa \ + REAL_RESULT="$(NCRESULT)" PROFILING="y" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + CREATE_LIB=yes \ + make_deps=yes +pncl: profiling-native-code-library + +# packs byte-code objects +pack-byte-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \ + REAL_RESULT="$(BCRESULT)" \ + PACK_LIB=yes make_deps=yes +pabc: pack-byte-code + +# packs native-code objects +pack-native-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(NCRESULT).cmx $(NCRESULT).o \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + PACK_LIB=yes make_deps=yes +panc: pack-native-code + +# generates HTML-documentation +htdoc: doc/$(RESULT)/html + +# generates Latex-documentation +ladoc: doc/$(RESULT)/latex + +# generates PostScript-documentation +psdoc: doc/$(RESULT)/latex/doc.ps + +# generates PDF-documentation +pdfdoc: doc/$(RESULT)/latex/doc.pdf + +# generates all supported forms of documentation +doc: htdoc ladoc psdoc pdfdoc + +########################################################################### +# LOW LEVEL RULES + +$(REAL_RESULT): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS) + $(REAL_OCAMLFIND) $(REAL_OCAMLC) \ + $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ + $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \ + $(REAL_IMPL) + +nolink: $(REAL_IMPL_INTF) $(OBJ_LINK) + +ifdef WIN32 +$(REAL_RESULT).dll: $(REAL_IMPL_INTF) $(OBJ_LINK) + $(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \ + -o $@ $(REAL_IMPL) +endif + +%$(TOPSUFFIX): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) + $(REAL_OCAMLFIND) $(OCAMLMKTOP) \ + $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ + $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \ + $(REAL_IMPL) + +.SUFFIXES: .mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \ + .mly .di .d .$(EXT_LIB) .idl %.oxridl .c .$(EXT_CXX) .h .so \ + .rep .zog .glade + +ifndef STATIC +ifdef MINGW +$(DLLSONAME): $(OBJ_LINK) + $(CC) $(CFLAGS) $(CFLAGS_WIN32) $(OBJ_LINK) -shared -o $@ \ + -Wl,--whole-archive $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/lib%.a))) \ + $(OCAMLLIBPATH)/ocamlrun.a \ + -Wl,--export-all-symbols \ + -Wl,--no-whole-archive +else +ifdef MSVC +$(DLLSONAME): $(OBJ_LINK) + link /NOLOGO /DLL /OUT:$@ $(OBJ_LINK) \ + $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/%.lib))) \ + $(OCAMLLIBPATH)/ocamlrun.lib + +else +$(DLLSONAME): $(OBJ_LINK) + $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \ + -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) \ + $(OCAMLMKLIB_FLAGS) +endif +endif +endif + +ifndef LIB_PACK_NAME +$(RESULT).cma: $(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) + $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) \ + $(OBJS_LIBS) -o $@ $(OCAMLBLDFLAGS) $(REAL_IMPL) + +$(RESULT).cmxa $(RESULT).$(EXT_LIB): $(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS) + $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(ALL_LDFLAGS) $(OBJS_LIBS) \ + $(OCAMLNLDFLAGS) -o $@ $(REAL_IMPL) +else +ifdef BYTE_OCAML +$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo: $(REAL_IMPL_INTF) + $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmo $(REAL_IMPL) +else +$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx: $(REAL_IMPL_INTF) + $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmx $(REAL_IMPL) +endif + +$(RESULT).cma: $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) + $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) \ + $(OBJS_LIBS) -o $@ $(OCAMLBLDFLAGS) $(LIB_PACK_NAME).cmo + +$(RESULT).cmxa $(RESULT).$(EXT_LIB): $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx $(EXTRADEPS) $(RESULTDEPS) + $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(ALL_LDFLAGS) $(OBJS_LIBS) \ + $(OCAMLNLDFLAGS) -o $@ $(LIB_PACK_NAME).cmx +endif + +$(RES_CLIB): $(OBJ_LINK) +ifndef MSVC + ifneq ($(strip $(OBJ_LINK)),) + $(AR) rcs $@ $(OBJ_LINK) + endif +else + ifneq ($(strip $(OBJ_LINK)),) + lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK) + endif +endif + +.mli.cmi: $(EXTRADEPS) + $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ + if [ -z "$$pp" ]; then \ + echo $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c $(THREAD_FLAG) $(ANNOT_FLAG) \ + $(OCAMLFLAGS) $(INCFLAGS) $<; \ + $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c $(THREAD_FLAG) $(ANNOT_FLAG) \ + $(OCAMLFLAGS) $(INCFLAGS) $<; \ + else \ + echo $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \ + $(OCAMLFLAGS) $(INCFLAGS) $<; \ + $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \ + $(OCAMLFLAGS) $(INCFLAGS) $<; \ + fi + +.ml.cmi .ml.$(EXT_OBJ) .ml.cmx .ml.cmo: $(EXTRADEPS) + $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ + if [ -z "$$pp" ]; then \ + echo $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c $(ALL_OCAMLCFLAGS) $<; \ + $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c $(ALL_OCAMLCFLAGS) $<; \ + else \ + echo $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \ + $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \ + fi + +ifdef PACK_LIB +$(REAL_RESULT).cmo $(REAL_RESULT).cmx $(REAL_RESULT).o: $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) + $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack $(ALL_LDFLAGS) \ + $(OBJS_LIBS) -o $@ $(REAL_IMPL) +endif + +.PRECIOUS: %.ml +%.ml: %.mll + $(OCAMLLEX) $< + +.PRECIOUS: %.ml %.mli +%.ml %.mli: %.mly + $(OCAMLYACC) $(YFLAGS) $< + $(QUIET)pp=`sed -n -e 's/.*(\*pp \([^*]*\) \*).*/\1/p;q' $<`; \ + if [ ! -z "$$pp" ]; then \ + mv $*.ml $*.ml.temporary; \ + echo "(*pp $$pp $(PPFLAGS)*)" > $*.ml; \ + cat $*.ml.temporary >> $*.ml; \ + rm $*.ml.temporary; \ + mv $*.mli $*.mli.temporary; \ + echo "(*pp $$pp $(PPFLAGS)*)" > $*.mli; \ + cat $*.mli.temporary >> $*.mli; \ + rm $*.mli.temporary; \ + fi + + +.PRECIOUS: %.ml +%.ml: %.rep + $(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $< + +.PRECIOUS: %.ml +%.ml: %.zog + $(CAMELEON_ZOGGY) $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@ + +.PRECIOUS: %.ml +%.ml: %.glade + $(OCAML_GLADECC) $(OCAML_GLADECC_FLAGS) $< > $@ + +.PRECIOUS: %.ml %.mli +%.ml %.mli: %.oxridl + $(OXRIDL) $< + +.PRECIOUS: %.ml %.mli %_stubs.c %.h +%.ml %.mli %_stubs.c %.h: %.idl + $(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \ + $(CAMLIDLFLAGS) $< + $(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi + +.c.$(EXT_OBJ): + $(OCAMLC) -c -cc "$(CC)" -ccopt "$(CFLAGS) \ + $(CPPFLAGS) $(CPPFLAGS_WIN32) \ + $(CFLAGS_WIN32) $(CINCFLAGS) $(CFLAG_O)$@ " $< + +.$(EXT_CXX).$(EXT_OBJ): + $(CXX) -c $(CXXFLAGS) $(CINCFLAGS) $(CPPFLAGS) \ + -I'$(OCAMLLIBPATH)' \ + $< $(CFLAG_O)$@ + +$(MLDEPDIR)/%.d: %.ml + $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi + $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ + if [ -z "$$pp" ]; then \ + echo $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ + $(DINCFLAGS) $< \> $@; \ + $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ + $(DINCFLAGS) $< > $@; \ + else \ + echo $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ + -pp \"$$pp $(PPFLAGS)\" $(DINCFLAGS) $< \> $@; \ + $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ + -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \ + fi + +$(BCDIDIR)/%.di $(NCDIDIR)/%.di: %.mli + $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi + $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ + if [ -z "$$pp" ]; then \ + echo $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(DINCFLAGS) $< \> $@; \ + $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(DINCFLAGS) $< > $@; \ + else \ + echo $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ + -pp \"$$pp $(PPFLAGS)\" $(DINCFLAGS) $< \> $@; \ + $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ + -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \ + fi + +doc/$(RESULT)/html: $(DOC_FILES) + rm -rf $@ + mkdir -p $@ + $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ + if [ -z "$$pp" ]; then \ + echo $(OCAMLDOC) -html -d $@ $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \ + $(OCAMLDOC) -html -d $@ $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \ + else \ + echo $(OCAMLDOC) -pp \"$$pp $(PPFLAGS)\" -html -d $@ $(OCAMLDOCFLAGS) \ + $(INCFLAGS) $(DOC_FILES); \ + $(OCAMLDOC) -pp "$$pp $(PPFLAGS)" -html -d $@ $(OCAMLDOCFLAGS) \ + $(INCFLAGS) $(DOC_FILES); \ + fi + +doc/$(RESULT)/latex: $(DOC_FILES) + rm -rf $@ + mkdir -p $@ + $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ + if [ -z "$$pp" ]; then \ + echo $(OCAMLDOC) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) \ + $(DOC_FILES) -o $@/doc.tex; \ + $(OCAMLDOC) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES) \ + -o $@/doc.tex; \ + else \ + echo $(OCAMLDOC) -pp \"$$pp $(PPFLAGS)\" -latex $(OCAMLDOCFLAGS) \ + $(INCFLAGS) $(DOC_FILES) -o $@/doc.tex; \ + $(OCAMLDOC) -pp "$$pp $(PPFLAGS)" -latex $(OCAMLDOCFLAGS) \ + $(INCFLAGS) $(DOC_FILES) -o $@/doc.tex; \ + fi + +doc/$(RESULT)/latex/doc.ps: doc/$(RESULT)/latex + cd doc/$(RESULT)/latex && \ + $(LATEX) doc.tex && \ + $(LATEX) doc.tex && \ + $(DVIPS) $(DVIPSFLAGS) doc.dvi -o $(@F) + +doc/$(RESULT)/latex/doc.pdf: doc/$(RESULT)/latex/doc.ps + cd doc/$(RESULT)/latex && $(PS2PDF) $(<F) + +define make_subproj +.PHONY: +subproj_$(1): + $$(eval $$(call PROJ_$(1))) + $(QUIET)if [ "$(SUBTARGET)" != "all" ]; then \ + $(MAKE) -f $(OCAMLMAKEFILE) $(SUBTARGET); \ + fi +endef + +$(foreach subproj,$(SUBPROJS),$(eval $(call make_subproj,$(subproj)))) + +.PHONY: +subprojs: $(SUBPROJS:%=subproj_%) + +########################################################################### +# (UN)INSTALL RULES FOR LIBRARIES + +.PHONY: libinstall +libinstall: all + $(QUIET)printf "\nInstalling library with ocamlfind\n" + $(OCAMLFIND) install $(OCAMLFIND_INSTFLAGS) $(RESULT) META $(LIBINSTALL_FILES) + $(QUIET)printf "\nInstallation successful.\n" + +.PHONY: libuninstall +libuninstall: + $(QUIET)printf "\nUninstalling library with ocamlfind\n" + $(OCAMLFIND) remove $(OCAMLFIND_INSTFLAGS) $(RESULT) + $(QUIET)printf "\nUninstallation successful.\n" + +.PHONY: rawinstall +rawinstall: all + $(QUIET)printf "\nInstalling library to: $(OCAML_LIB_INSTALL)\n" + -install -d $(OCAML_LIB_INSTALL) + for i in $(LIBINSTALL_FILES); do \ + if [ -f $$i ]; then \ + install -c -m 0644 $$i $(OCAML_LIB_INSTALL); \ + fi; \ + done + $(QUIET)printf "\nInstallation successful.\n" + +.PHONY: rawuninstall +rawuninstall: + $(QUIET)printf "\nUninstalling library from: $(OCAML_LIB_INSTALL)\n" + cd $(OCAML_LIB_INSTALL) && rm $(notdir $(LIBINSTALL_FILES)) + $(QUIET)printf "\nUninstallation successful.\n" + +########################################################################### +# MAINTAINANCE RULES + +.PHONY: clean +clean:: + rm -f $(TARGETS) $(TRASH) + rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR) + +.PHONY: cleanup +cleanup:: + rm -f $(NONEXECS) $(TRASH) + rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR) + +.PHONY: clean-doc +clean-doc:: + rm -rf doc + +.PHONY: nobackup +nobackup: + rm -f *.bak *~ *.dup diff --git a/examples/http.ml b/examples/http.ml new file mode 100644 index 0000000..85964a9 --- /dev/null +++ b/examples/http.ml @@ -0,0 +1,688 @@ +(*pp $PP *) + +let non_blocking_queues = ref 3 +let maybe_blocking_queues = ref 1 +let files_path = ref "" +let port = ref 8080 + +let usage = "usage: http [options] /path/to/files" + +let () = + let pnum = ref 0 in + let arg s = + incr pnum; + if !pnum > 1 then + (Printf.eprintf "Error: too many arguments\n"; exit 1) + else + files_path := s + in + Arg.parse + [ + "--non_blocking_queues", Arg.Int (fun i -> non_blocking_queues := i), + (Printf.sprintf + "Number of non-blocking queues. (default: %d)" !non_blocking_queues); + "--maybe_blocking_queues", Arg.Int (fun i -> maybe_blocking_queues := i), + (Printf.sprintf + "Number of maybe-blocking queues. (default: %d)" !maybe_blocking_queues) ; + "--port", Arg.Int (fun i -> port := i), + (Printf.sprintf + "Port used to bind the server. (default: %d)" !port) ; + ] arg usage ; + if !files_path = "" then + ( + Printf.printf "%s\n" usage; + exit 1 + ) + + +type priority = + Maybe_blocking + | Non_blocking + +let scheduler = Duppy.create () + +type http_method = Post | Get + +type http_protocol = Http_11 | Http_10 + +let string_of_protocol = + function + | Http_11 -> "HTTP/1.1" + | Http_10 -> "HTTP/1.0" + +let protocol_of_string = + function + | "HTTP/1.1" -> Http_11 + | "HTTP/1.0" -> Http_10 + | _ -> assert false + +let string_of_method = + function + | Post -> "POST" + | Get -> "GET" + +let method_of_string = + function + | "POST" -> Post + | "GET" -> Get + | _ -> assert false + +type data = None | String of string | File of Unix.file_descr + +type request = + { request_protocol : http_protocol ; + request_method : http_method ; + request_uri : string ; + request_headers : (string*string) list ; + request_data : data } + +type reply = + { reply_protocol : http_protocol ; + reply_status : int*string ; + reply_headers : (string*string) list ; + reply_data : data } + +exception Assoc of string + +let assoc_uppercase x y = + try + List.iter + (fun (l,v) -> if String.uppercase l = x then + raise (Assoc v)) y ; + raise Not_found + with + | Assoc s -> s + +let server = "dhttpd" + +let html_template = + Printf.sprintf + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \ + \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\r\n\ + <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\r\n\ + %s</html>" + +let server_error status protocol = + let (code,explanation) = status in + let data = + String + (html_template + (Printf.sprintf + "<head><title>%s</title></head>\r\n\ + <body>%s !</body>" explanation explanation)) + in + { reply_protocol = protocol ; + reply_status = status ; + reply_headers = [ "Content-Type","text/html; charset=UTF-8"; + "Server", server ] ; + reply_data = data } + +let error_404 = + server_error (404,"File Not Found") + +let error_500 = + server_error (500,"Bad Request") Http_10 + +let error_403 = + server_error (403,"Forbidden") + +let http_302 protocol uri = + { reply_protocol = protocol ; + reply_status = (302,"Found") ; + reply_headers = ["Location",uri]; + reply_data = String "" } + +type socket_status = Keep | Close + +let send_reply h reply = + let write s = + duppy_write + s + with + { priority = Non_blocking ; + handler = h } + in + let (code,status) = reply.reply_status in + let http_header = + Printf.sprintf + "%s %d %s\r\n\ + %s\r\n\ + \r\n" + (string_of_protocol reply.reply_protocol) code status + (String.concat "\r\n" + (List.map + (fun (x,y) -> + Printf.sprintf "%s: %s" x y) reply.reply_headers)) + in + duppy_do + write http_header ; + begin + match reply.reply_data with + | String s -> + write s + | File fd -> + let stats = Unix.fstat fd in + let ba = + Bigarray.Array1.map_file + fd Bigarray.char Bigarray.c_layout false + (stats.Unix.st_size) + in + let close () = + try + Unix.close fd + with + | _ -> () + in + let on_error e = + close () ; + h.Duppy.Monad.Io.on_error e + in + let h = + { h with + Duppy.Monad.Io. + on_error = on_error } + in + duppy_do + duppy_write_bigarray + ba + with + { priority = Non_blocking ; + handler = h } ; + duppy_return (close ()) + done + | None -> duppy_return () + end + done + +let parse_headers headers = + let split_header l h = + try + let rex = Pcre.regexp "([^:\\r\\n]+):\\s*([^\\r\\n]+)" in + let sub = Pcre.exec ~rex h in + duppy_return + ((Pcre.get_substring sub 1, + Pcre.get_substring sub 2) :: l) + with + | Not_found -> duppy_raise error_500 + in + duppy_fold_left split_header [] headers + +let index_uri path index protocol uri = + let uri = + try + let ret = + Pcre.extract ~rex:(Pcre.regexp "([^\\?]*)\\?") + uri + in + ret.(1) + with + | Not_found -> uri + in + try + if Sys.is_directory + (Printf.sprintf "%s%s" path uri) + then + if uri.[String.length uri - 1] <> '/' then + duppy_raise (http_302 protocol (Printf.sprintf "%s/" uri)) + else + begin + let index = Printf.sprintf "%s/%s" uri index in + if Sys.file_exists + (Printf.sprintf "%s/%s" path index) then + duppy_return index + else + duppy_return uri + end + else + duppy_return uri + with + | _ -> duppy_return uri + +let file_request path _ request = + let uri = + try + let ret = + Pcre.extract ~rex:(Pcre.regexp "([^\\?]*)\\?.*") + request.request_uri + in + ret.(1) + with + | Not_found -> request.request_uri + in + duppy uri = + index_uri path "index.html" + request.request_protocol uri + in + let fname = + Printf.sprintf "%s%s" path uri + in + if Sys.file_exists fname then + try + let fd = Unix.openfile fname [Unix.O_RDONLY] 0o640 in + let stats = Unix.fstat fd in + let headers = + [ "Server", server; + "Content-Length", string_of_int (stats.Unix.st_size) ] + in + let headers = + if Pcre.pmatch ~rex:(Pcre.regexp "\\.html$") fname then + ("Content-Type","text/html") :: headers + else if Pcre.pmatch ~rex:(Pcre.regexp "\\.css$") fname then + ("Content-Type","text/css") :: headers + else + headers + in + duppy_raise + { reply_protocol = request.request_protocol ; + reply_status = (200,"OK") ; + reply_headers = headers ; + reply_data = File fd } + with + | _ -> duppy_raise (error_403 request.request_protocol) + else + duppy_raise (error_404 request.request_protocol) + +let file_handler = + (fun _ -> duppy_return true),file_request !files_path + +let cgi_handler process path h request = + let uri,args,suffix = + try + let ret = + Pcre.extract ~rex:(Pcre.regexp "([^\\?]*)\\?(.*)") + request.request_uri + in + begin + try + let ans = + Pcre.extract ~rex:(Pcre.regexp "^([^/]*)/([^&=]*)$") + ret.(2) + in + ret.(1),ans.(1),ans.(2) + with + | Not_found -> ret.(1),ret.(2),"" + end + with + | Not_found -> request.request_uri,"","" + in + duppy script = + index_uri path "index.php" + request.request_protocol + uri + in + let script = + Printf.sprintf "%s%s" path script + in + let env = + Printf.sprintf + "export SERVER_SOFTWARE=Duppy-httpd/1.0; \ + export SERVER_NAME=localhost; \ + export GATEWAY_INTERFACE=CGI/1.1; \ + export SERVER_PROTOCOL=%s; \ + export SERVER_PORT=%d; \ + export REQUEST_METHOD=%s; \ + export REQUEST_URI=%s; \ + export REDIRECT_STATUS=200; \ + export SCRIPT_FILENAME=%s" + (string_of_protocol (request.request_protocol)) + !port + (string_of_method (request.request_method)) + (Filename.quote uri) + (Filename.quote script) + in + let env = + Printf.sprintf "%s; export QUERY_STRING=%s" + env + (Filename.quote args) + in + let env = + let tr_suffix = + Printf.sprintf "%s%s" path suffix + in + (* Trick ! *) + let tr_suffix = + Printf.sprintf "%s/%s" (Filename.dirname tr_suffix) + (Filename.basename tr_suffix) + in + Printf.sprintf "%s; export PATH_TRANSLATED=%s; \ + export PATH_INFO=%s" + env + (Filename.quote tr_suffix) + (Filename.quote suffix) + in + let sanitize s = + Pcre.replace ~pat:"-" ~templ:"_" (String.uppercase s) + in + let headers = + List.map (fun (x,y) -> (sanitize x,y)) request.request_headers + in + let append env key = + if List.mem_assoc key headers then + Printf.sprintf "%s; export %s=%s" + env key (Filename.quote (List.assoc key headers)) + else + env + in + let env = append env "CONTENT_TYPE" in + let env = append env "CONTENT_LENGTH" in + duppy env = + if List.mem_assoc "AUTHORIZATION" headers then + begin + let ret = + Pcre.extract ~rex:(Pcre.regexp "(^[^\\s]*\\s.*)$") + (List.assoc "AUTHORIZATION" headers) + in + if Array.length ret > 0 then + duppy_return (Printf.sprintf "%s; extract AUTH_TYPE=%s" env (ret.(1))) + else + duppy_raise error_500 + end + else + duppy_return env + in + let f env (x,y) = + Printf.sprintf "%s; export HTTP_%s=%s" + env x (Filename.quote y) + in + let env = List.fold_left f env headers in + let data = + match request.request_data with + | None -> "" + | String s -> s + | _ -> assert false (* not implemented *) + in + let process = + Printf.sprintf "%s; %s 2>/dev/null" + env process + in + let in_c,out_c = + Unix.open_process process + in + let out_s = + Unix.descr_of_out_channel out_c + in + let h = + { h with + Duppy.Monad.Io. + socket = out_s ; + data = "" + } + in + duppy () = + duppy_write + data + with + { priority = Non_blocking ; + handler = h } + in + let in_s = + Unix.descr_of_in_channel in_c + in + let h = + { h with + Duppy.Monad.Io. + socket = in_s ; + data = "" + } + in + duppy headers = + duppy_read + Duppy.Io.Split "[\r]?\n[\r]?\n" + with + { priority = Non_blocking ; + handler = h } + in + duppy data = + duppy_try + duppy_read_all + in_s + with + { priority = Non_blocking ; + scheduler = h.Duppy.Monad.Io.scheduler } + with + | (s,_) -> duppy_return s + in + let data = + Printf.sprintf "%s%s" h.Duppy.Monad.Io.data data + in + ignore(Unix.close_process (in_c,out_c)) ; + duppy headers = + let headers = Pcre.split ~pat:"\r\n" headers in + parse_headers headers + in + duppy status,headers = + if List.mem_assoc "Status" headers then + try + let ans = Pcre.extract ~rex:(Pcre.regexp "([\\d]+)\\s(.*)") + (List.assoc "Status" headers) + in + duppy_return + ((int_of_string ans.(1), + ans.(2)), + List.filter (fun (x,y) -> x <> "Status") headers) + with _ -> duppy_raise error_500 + else duppy_return ((200,"OK"),headers) + in + let headers = + ("Content-length",string_of_int (String.length data)):: + headers + in + duppy_raise + { reply_protocol = request.request_protocol ; + reply_status = status ; + reply_headers = headers ; + reply_data = String data } + +let php_handler = + (fun request -> + duppy uri = + index_uri !files_path "index.php" + request.request_protocol + request.request_uri + in + duppy_return (Pcre.pmatch ~rex:(Pcre.regexp "\\.php$") uri)), + cgi_handler "php-cgi" !files_path + +let handlers = [php_handler;file_handler] + +let handle_request h request = + let f (check,handler) = + duppy check = check request in + if check then + handler h request + else + duppy_return () + in + duppy_try + duppy_do + duppy_iter f handlers ; + duppy_return (error_404 request.request_protocol) + done + with + | reply -> duppy_return reply + +let parse_request h r = + try + let headers = Pcre.split ~pat:"\r\n" r in + duppy request,headers = + match headers with + | e :: l -> + duppy headers = + parse_headers l + in + duppy_return (e,headers) + | _ -> duppy_raise error_500 + in + let rex = Pcre.regexp "([\\w]+)\\s([^\\s]+)\\s(HTTP/1.[01])" in + duppy http_method,uri,protocol = + try + let sub = Pcre.exec ~rex request in + let http_method,uri,protocol = + Pcre.get_substring sub 1, + Pcre.get_substring sub 2, + Pcre.get_substring sub 3 + in + duppy_return + (method_of_string http_method, + uri, + protocol_of_string protocol) + with + | _ -> duppy_raise error_500 + in + duppy data = + match http_method with + | Get -> duppy_return None + | Post -> + duppy len = + try + let length = assoc_uppercase "CONTENT-LENGTH" headers in + duppy_return (int_of_string length) + with + | Not_found -> duppy_return 0 + | _ -> duppy_raise error_500 + in + match len with + | 0 -> duppy_return None + | d -> + duppy data = + duppy_read + Duppy.Io.Length d + with + { priority = Non_blocking ; + handler = h } + in + duppy_return (String data) + in + duppy_return + { request_method = http_method ; + request_protocol = protocol ; + request_uri = uri ; + request_headers = headers ; + request_data = data } + with + | _ -> duppy_raise error_500 + +let handle_client socket = + (* Read and process lines *) + let on_error e = + error_500 + in + let h = + { Duppy.Monad.Io. + scheduler = scheduler ; + socket = socket ; + data = ""; + on_error = on_error } + in + let rec exec () = + duppy (keep,reply) = + duppy_try + duppy data = + duppy_read + Duppy.Io.Split "\r\n\r\n" + with + { priority = Non_blocking ; + handler = h } + in + duppy request = + parse_request h data + in + duppy reply = + handle_request h request + in + let close_header headers = + try + (assoc_uppercase "CONNECTION" headers) = "close" + with + | Not_found -> false + in + let keep = + if + request.request_protocol = Http_10 || + close_header request.request_headers || + close_header reply.reply_headers + then + Close + else + Keep + in + duppy_return (keep,reply) + with + | reply -> duppy_return (Close,reply) + in + duppy_do + send_reply h reply ; + if keep = Keep then + exec () + else + duppy_return () + done + in + let finish _ = + try + Unix.close socket + with + | _ -> () + in + duppy_run + exec () + with + { return = finish ; + raise = finish } + +let new_queue ~priority ~name () = + let priorities p = p = priority in + let queue () = + Duppy.queue scheduler ~log:(fun _ -> ()) ~priorities name + in + Thread.create queue () + +let bind_addr_inet = Unix.inet_addr_of_string "0.0.0.0" +let bind_addr = Unix.ADDR_INET(bind_addr_inet, !port) +let max_conn = 100 +let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 +let () = + (* See http://caml.inria.fr/mantis/print_bug_page.php?bug_id=4640 + * for this: we want Unix EPIPE error and not SIGPIPE, which + * crashes the program.. *) + Sys.set_signal Sys.sigpipe Sys.Signal_ignore; + ignore (Unix.sigprocmask Unix.SIG_BLOCK [Sys.sigpipe]); + Unix.setsockopt sock Unix.SO_REUSEADDR true ; + let rec incoming _ = + begin + try + let (s,caller) = Unix.accept sock in + handle_client s + with e -> + Printf.printf "Failed to accept new client: %S\n" + (Printexc.to_string e) + end ; + [{ Duppy.Task. + priority = Non_blocking ; + events = [`Read sock] ; + handler = incoming }] + in + begin + try + Unix.bind sock bind_addr + with + | Unix.Unix_error(Unix.EADDRINUSE, "bind", "") -> + failwith (Printf.sprintf "port %d already taken" !port) + end ; + Unix.listen sock max_conn ; + Duppy.Task.add scheduler + { Duppy.Task. + priority = Non_blocking ; + events = [`Read sock] ; + handler = incoming } ; + for i = 1 to !non_blocking_queues do + ignore(new_queue ~priority:Non_blocking + ~name:(Printf.sprintf "Non blocking queue #%d" i) + ()) + done ; + for i = 1 to !maybe_blocking_queues do + ignore(new_queue ~priority:Maybe_blocking + ~name:(Printf.sprintf "Maybe blocking queue #%d" i) + ()) + done ; + Duppy.queue scheduler ~log:(fun _ -> ()) "root" diff --git a/examples/telnet.ml b/examples/telnet.ml new file mode 100644 index 0000000..f1e60a2 --- /dev/null +++ b/examples/telnet.ml @@ -0,0 +1,181 @@ +(*pp $PP *) + +type priority = Non_blocking | Maybe_blocking +let io_priority = Non_blocking + +(* Create scheduler *) +let scheduler = Duppy.create () + +(* Create two queues, + * one for non blocking events + * and another for blocking + * events *) +let new_queue ~priority ~name () = + let log = + Printf.printf "%s: %s\n%!" name + in + let priorities p = p = priority in + let queue () = + Duppy.queue scheduler ~log ~priorities name + in + Thread.create queue () + +let th = + ignore(new_queue ~priority:Non_blocking + ~name:"Non blocking queue" ()) ; + ignore(new_queue ~priority:Maybe_blocking + ~name:"Maybe blocking queue #1" ()) ; + new_queue ~priority:Maybe_blocking + ~name:"Maybe blocking queue #2" () + +let exec_command s () = + let chan = Unix.open_process_in s in + let rec aux () = + match + try Some (input_line chan) with End_of_file -> None + with + | None -> [] + | Some s -> s::(aux ()) + in + let l = aux () in + ignore (Unix.close_process_in chan) ; + duppy_return (String.concat "\r\n" l) + + +let commands = Hashtbl.create 10 +let () = Hashtbl.add commands "hello" (false,fun () -> duppy_return "world") ; + Hashtbl.add commands "foo" (false,fun () -> duppy_return "bar") ; + Hashtbl.add commands "uptime" (true,exec_command "uptime") ; + Hashtbl.add commands "date" (true,exec_command "date") ; + Hashtbl.add commands "whoami" (true,exec_command "whoami") ; + Hashtbl.add commands "sleep" (true,exec_command "sleep 15") ; + Hashtbl.add commands "exit" (true,fun () -> duppy_raise ()) +(* Add commands here *) +let help = Buffer.create 10 +let () = Buffer.add_string help "List of commands:" ; + Hashtbl.iter + (fun x _ -> Buffer.add_string help (Printf.sprintf "\r\n%s" x)) + commands ; + Hashtbl.add commands "help" (false,fun () -> duppy_return (Buffer.contents help)) + +let handle_client socket = + let on_error e = + match e with + | Duppy.Io.Io_error -> + Printf.printf "Client disconnected" + | Duppy.Io.Unix (c,p,m) -> + Printf.printf "%s" (Printexc.to_string + (Unix.Unix_error (c,p,m))) + | Duppy.Io.Unknown e -> + Printf.printf "%s" (Printexc.to_string e) + in + let h = + { Duppy.Monad.Io. + scheduler = scheduler ; + socket = socket ; + data = ""; + on_error = on_error } + in + (* Read and process lines *) + let rec exec () = + duppy req = + duppy_read + Duppy.Io.Split "[\r\n]+" + with + { priority = io_priority ; + handler = h } + in + duppy ans = + try + let blocking,command = Hashtbl.find commands req in + if not blocking then + command () + else + begin + duppy_exec + command () + with + { priority = Maybe_blocking ; + handler = h } + end + with + | Not_found -> + duppy_return "ERROR: unknown command, type \"help\" to get a \ + list of commands." + in + duppy_do + duppy_write + "BEGIN\r\n"; + ans; + "\r\nEND\r\n" + with + { priority = io_priority ; + handler = h } ; + exec () + done + in + let close () = + try + Unix.close socket + with + | _ -> () + in + let return () = + let on_error e = + on_error e ; + close () + in + Duppy.Io.write ~priority:io_priority + ~on_error + ~exec:close scheduler + ~string:"Bye!\r\n" socket + in + duppy_run + exec () + with + { return = return ; + raise = close } + +open Unix + +let port = 4123 +let bind_addr_inet = inet_addr_of_string "0.0.0.0" +let bind_addr = ADDR_INET(bind_addr_inet, port) +let max_conn = 10 +let sock = socket PF_INET SOCK_STREAM 0 + +let () = + setsockopt sock SO_REUSEADDR true ; + let rec incoming _ = + begin + try + let (s,caller) = accept sock in + let ip = + let a = match caller with + | ADDR_INET (a,_) -> a + | _ -> assert false + in + try + (gethostbyaddr a).h_name + with + | Not_found -> string_of_inet_addr a + in + Printf.printf "New client: %s\n" ip ; + handle_client s + with e -> + Printf.printf "Failed to accept new client: %S\n" (Printexc.to_string e) + end ; + [{ Duppy.Task.priority = io_priority ; + Duppy.Task.events = [`Read sock] ; + Duppy.Task.handler = incoming }] + in + begin try bind sock bind_addr with + | Unix.Unix_error(Unix.EADDRINUSE, "bind", "") -> + failwith (Printf.sprintf "port %d already taken" port) + end ; + listen sock max_conn ; + Duppy.Task.add scheduler + { Duppy.Task.priority = io_priority ; + Duppy.Task.events = [`Read sock] ; + Duppy.Task.handler = incoming } ; + Thread.join th |