-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
479 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
dist | ||
_obuild | ||
ocp-build.* | ||
_build | ||
*.install | ||
*.native | ||
*.byte |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,6 @@ | ||
0.2 (2014-04-24): | ||
* Functor output signature is now explicit | ||
* Build system switched to topkg+ocamlbuild | ||
|
||
0.1 (2013-06-10): | ||
* first alpha release |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,14 @@ | ||
UNIX ?= $(shell if ocamlfind query unix >/dev/null 2>&1; then echo --flag unix; fi) | ||
LWT ?= $(shell if ocamlfind query lwt.unix >/dev/null 2>&1; then echo --flag lwt; fi) | ||
PREFIX=/usr/local | ||
|
||
all: build | ||
|
||
dist/setup: | ||
obuild configure $(UNIX) $(LWT) | ||
|
||
build: dist/setup | ||
obuild build | ||
build: | ||
ocaml pkg/build.ml native=true native-dynlink=true unix=true lwt=true | ||
|
||
install: build | ||
ocamlfind install smtp dist/build/lib-smtp/* dist/build/lib-smtp_unix/* dist/build/lib-smtp_lwt/* lib/META | ||
|
||
uninstall: | ||
ocamlfind remove smtp | ||
|
||
reinstall: | ||
$(MAKE) uninstall || true | ||
$(MAKE) install | ||
opam-installer --prefix=$(PREFIX) *.install | ||
|
||
PHONY: clean | ||
|
||
clean: | ||
obuild clean | ||
ocamlbuild -clean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<**/*.{ml,mli}> : bin_annot | ||
<src> : include | ||
<test> : include | ||
<src/smtp_lwt.{ml,mli}> : package(lwt) | ||
<src/smtp_unix.{ml}> : use_unix | ||
<test/test_lwt.{ml,native,byte}> : package(lwt.unix) | ||
<test/test_unix.{ml,native,byte}> : use_unix |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
opam-version: "1" | ||
maintainer: "Vincent Bernardoff <[email protected]>" | ||
authors: ["Vincent Bernardoff <[email protected]>"] | ||
license: "ISC" | ||
tags: [ "smtp" ] | ||
depends: ["ocamlfind"] | ||
depopts: ["lwt"] | ||
build: | ||
[ | ||
[ "ocaml" "pkg/git.ml" ] | ||
[ "ocaml" "pkg/build.ml" "native=%{ocaml-native}%" | ||
"native-dynlink=%{ocaml-native}%" | ||
"unix=%{base-unix:installed}%" | ||
"lwt=%{lwt:installed}%" | ||
] # TODO FIXME | ||
] |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#!/usr/bin/env ocaml | ||
#directory "pkg" | ||
#use "topkg.ml" | ||
|
||
let unix = Env.bool "unix" | ||
let lwt = Env.bool "lwt" | ||
let () = | ||
Pkg.describe "smtp" ~builder:`OCamlbuild [ | ||
Pkg.lib "pkg/META"; | ||
Pkg.lib ~exts:Exts.module_library "src/smtp"; | ||
Pkg.lib ~cond:lwt ~exts:Exts.library "src/smtp_lwt"; | ||
Pkg.lib ~cond:unix ~exts:Exts.library "src/smtp_unix"; | ||
Pkg.bin ~cond:lwt ~auto:true ~dst:"smtp_test_lwt" "test/test_lwt"; | ||
Pkg.bin ~cond:unix ~auto:true ~dst:"smtp_test_unix" "test/test_unix"; | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,303 @@ | ||
(*--------------------------------------------------------------------------- | ||
Copyright (c) 2014 Daniel C. Bünzli. All rights reserved. | ||
Distributed under the BSD3 license, see license at the end of the file. | ||
%%NAME%% release %%VERSION%% | ||
---------------------------------------------------------------------------*) | ||
|
||
(* Public api *) | ||
|
||
(** Build environment access *) | ||
module type Env = sig | ||
val bool : string -> bool | ||
(** [bool key] declares [key] as being a boolean key in the environment. | ||
Specifing key=(true|false) on the command line becomes mandatory. *) | ||
|
||
val native : bool | ||
(** [native] is [bool "native"]. *) | ||
|
||
val native_dynlink : bool | ||
(** [native_dylink] is [bool "native-dynlink"] *) | ||
end | ||
|
||
(** Exts defines sets of file extensions. *) | ||
module type Exts = sig | ||
val interface : string list | ||
(** [interface] is [[".mli"; ".cmi"; ".cmti"]] *) | ||
|
||
val interface_opt : string list | ||
(** [interface_opt] is [".cmx" :: interface] *) | ||
|
||
val library : string list | ||
(** [library] is [[".cma"; ".cmxa"; ".cmxs"; ".a"]] *) | ||
|
||
val module_library : string list | ||
(** [module_library] is [(interface_opt @ library)]. *) | ||
end | ||
|
||
(** Package description. *) | ||
module type Pkg = sig | ||
type builder = [ `OCamlbuild | `Other of string * string ] | ||
(** The type for build tools. Either [`OCamlbuild] or an | ||
[`Other (tool, bdir)] tool [tool] that generates its build artefacts | ||
in [bdir]. *) | ||
|
||
type moves | ||
(** The type for install moves. *) | ||
|
||
type field = ?cond:bool -> ?exts:string list -> ?dst:string -> string -> moves | ||
(** The type for field install functions. A call | ||
[field cond exts dst path] generates install moves as follows: | ||
{ul | ||
{- If [cond] is [false] (defaults to [true]), no move is generated.} | ||
{- If [exts] is present, generates a move for each path in | ||
the list [List.map (fun e -> path ^ e) exts].} | ||
{- If [dst] is present this path is used as the move destination | ||
(allows to install in subdirectories). If absent [dst] is | ||
[Filename.basename path].} *) | ||
|
||
val lib : field | ||
val bin : ?auto:bool -> field | ||
(** If [auto] is true (defaults to false) generates | ||
[path ^ ".native"] if {!Env.native} is [true] and | ||
[path ^ ".byte"] if {!Env.native} is [false]. *) | ||
val sbin : ?auto:bool -> field (** See {!bin}. *) | ||
val toplevel : field | ||
val share : field | ||
val share_root : field | ||
val etc : field | ||
val doc : field | ||
val misc : field | ||
val stublibs : field | ||
val man : field | ||
val describe : string -> builder:builder -> moves list -> unit | ||
(** [describe name builder moves] describes a package named [name] with | ||
builder [builder] and install moves [moves]. *) | ||
end | ||
|
||
(* Implementation *) | ||
|
||
module Topkg : sig | ||
val cmd : [`Build | `Explain | `Help ] | ||
val env : (string * bool) list | ||
val err_parse : string -> 'a | ||
val err_mdef : string -> 'a | ||
val err_miss : string -> 'a | ||
val err_file : string -> string -> 'a | ||
val warn_unused : string -> unit | ||
end = struct | ||
|
||
(* Parses the command line. The actual cmd execution occurs in the call | ||
to Pkg.describe. *) | ||
|
||
let err fmt = | ||
let k _ = exit 1 in | ||
Format.kfprintf k Format.err_formatter ("%s: " ^^ fmt ^^ "@.") Sys.argv.(0) | ||
|
||
let err_parse a = err "argument `%s' is not of the form key=(true|false)" a | ||
let err_mdef a = err "bool `%s' is defined more than once" a | ||
let err_miss a = err "argument `%s=(true|false)' is missing" a | ||
let err_file f e = err "%s: %s" f e | ||
let warn_unused k = | ||
Format.eprintf "%s: warning: environment key `%s` unused.@." Sys.argv.(0) k | ||
|
||
let cmd, env = | ||
let rec parse_env acc = function (* not t.r. *) | ||
| arg :: args -> | ||
begin try | ||
(* String.cut ... *) | ||
let len = String.length arg in | ||
let eq = String.index arg '=' in | ||
let bool = bool_of_string (String.sub arg (eq + 1) (len - eq - 1)) in | ||
let key = String.sub arg 0 eq in | ||
if key = "" then raise Exit else | ||
try ignore (List.assoc key acc); err_mdef key with | ||
| Not_found -> parse_env ((key, bool) :: acc) args | ||
with | ||
| Invalid_argument _ | Not_found | Exit -> err_parse arg | ||
end | ||
| [] -> acc | ||
in | ||
match List.tl (Array.to_list Sys.argv) with | ||
| "explain" :: args -> `Explain, parse_env [] args | ||
| ("help" | "-h" | "--help" | "-help") :: args -> `Help, parse_env [] args | ||
| args -> `Build, parse_env [] args | ||
end | ||
|
||
module Env : sig | ||
include Env | ||
val get : unit -> (string * bool) list | ||
end = struct | ||
let env = ref [] | ||
let get () = !env | ||
let add_bool key b = env := (key, b) :: !env | ||
let bool key = | ||
let b = try List.assoc key Topkg.env with | ||
| Not_found -> if Topkg.cmd = `Build then Topkg.err_miss key else true | ||
in | ||
add_bool key b; b | ||
|
||
let native = bool "native" | ||
let native_dynlink = bool "native-dynlink" | ||
end | ||
|
||
module Exts : Exts = struct | ||
let interface = [".mli"; ".cmi"; ".cmti"] | ||
let interface_opt = ".cmx" :: interface | ||
let library = [".cma"; ".cmxa"; ".cmxs"; ".a"] | ||
let module_library = (interface_opt @ library) | ||
end | ||
|
||
module Pkg : Pkg = struct | ||
type builder = [ `OCamlbuild | `Other of string * string ] | ||
type moves = (string * (string * string)) list | ||
type field = ?cond:bool -> ?exts:string list -> ?dst:string -> string -> moves | ||
|
||
let str = Printf.sprintf | ||
let warn_unused () = | ||
let keys = List.map fst Topkg.env in | ||
let keys_used = List.map fst (Env.get ()) in | ||
let unused = List.find_all (fun k -> not (List.mem k keys_used)) keys in | ||
List.iter Topkg.warn_unused unused | ||
|
||
let has_suffix = Filename.check_suffix | ||
let build_strings ?(exec_sep = " ") btool bdir mvs = | ||
let no_build = [ ".cmti"; ".cmt" ] in | ||
let install = Buffer.create 1871 in | ||
let exec = Buffer.create 1871 in | ||
let rec add_mvs current = function | ||
| (field, (src, dst)) :: mvs when field = current -> | ||
if List.exists (has_suffix src) no_build then | ||
Buffer.add_string install (str "\n \"?%s/%s\" {\"%s\"}" bdir src dst) | ||
else begin | ||
Buffer.add_string exec (str "%s%s" exec_sep src); | ||
Buffer.add_string install (str "\n \"%s/%s\" {\"%s\"}" bdir src dst); | ||
end; | ||
add_mvs current mvs | ||
| (((field, _) :: _) as mvs) -> | ||
if current <> "" (* first *) then Buffer.add_string install " ]\n"; | ||
Buffer.add_string install (str "%s: [" field); | ||
add_mvs field mvs | ||
| [] -> () | ||
in | ||
Buffer.add_string exec btool; | ||
add_mvs "" mvs; | ||
Buffer.add_string install " ]\n"; | ||
Buffer.contents install, Buffer.contents exec | ||
|
||
let pr = Format.printf | ||
let pr_explanation btool bdir pkg mvs = | ||
let env = Env.get () in | ||
let install, exec = build_strings ~exec_sep:" \\\n " btool bdir mvs in | ||
pr "@[<v>"; | ||
pr "Package name: %s@," pkg; | ||
pr "Build tool: %s@," btool; | ||
pr "Build directory: %s@," bdir; | ||
pr "Environment:@, "; | ||
List.iter (fun (k,v) -> pr "%s=%b@, " k v) (List.sort compare env); | ||
pr "@,Build invocation:@,"; | ||
pr " %s@,@," exec; | ||
pr "Install file:@,"; | ||
pr "%s@," install; | ||
pr "@]"; | ||
() | ||
|
||
let pr_help () = | ||
pr "Usage example:@\n %s" Sys.argv.(0); | ||
List.iter (fun (k,v) -> pr " %s=%b" k v) (List.sort compare (Env.get ())); | ||
pr "@." | ||
|
||
let build btool bdir pkg mvs = | ||
let install, exec = build_strings btool bdir mvs in | ||
let e = Sys.command exec in | ||
if e <> 0 then exit e else | ||
let install_file = pkg ^ ".install" in | ||
try | ||
let oc = open_out install_file in | ||
output_string oc install; flush oc; close_out oc | ||
with Sys_error e -> Topkg.err_file install_file e | ||
|
||
let mvs ?(drop_exts = []) field ?(cond = true) ?(exts = []) ?dst src = | ||
if not cond then [] else | ||
let mv src dst = (field, (src, dst)) in | ||
let expand exts s d = List.map (fun e -> mv (s ^ e) (d ^ e)) exts in | ||
let dst = match dst with None -> Filename.basename src | Some dst -> dst in | ||
let files = if exts = [] then [mv src dst] else expand exts src dst in | ||
let keep (_, (src, _)) = not (List.exists (has_suffix src) drop_exts) in | ||
List.find_all keep files | ||
|
||
let lib = | ||
let drop_exts = | ||
if Env.native && not Env.native_dynlink then [ ".cmxs" ] else | ||
if not Env.native then [ ".a"; ".cmx"; ".cmxa"; ".cmxs" ] else [] | ||
in | ||
mvs ~drop_exts "lib" | ||
|
||
let share = mvs "share" | ||
let share_root = mvs "share_root" | ||
let etc = mvs "etc" | ||
let toplevel = mvs "toplevel" | ||
let doc = mvs "doc" | ||
let misc = mvs "misc" | ||
let stublibs = mvs "stublib" | ||
let man = mvs "man" | ||
|
||
let bin_drops = if not Env.native then [ ".native" ] else [] | ||
let bin_mvs field ?(auto = false) ?cond ?exts ?dst src = | ||
let src, dst = | ||
if not auto then src, dst else | ||
let dst = match dst with | ||
| None -> Some (Filename.basename src) | ||
| Some _ as dst -> dst | ||
in | ||
let src = if Env.native then src ^ ".native" else src ^ ".byte" in | ||
src, dst | ||
in | ||
mvs ~drop_exts:bin_drops field ?cond ?dst src | ||
|
||
let bin = bin_mvs "bin" | ||
let sbin = bin_mvs "sbin" | ||
|
||
let describe pkg ~builder mvs = | ||
let mvs = List.sort compare (List.flatten mvs) in | ||
let btool, bdir = match builder with | ||
| `OCamlbuild -> "ocamlbuild -use-ocamlfind -classic-display", "_build" | ||
| `Other (btool, bdir) -> btool, bdir | ||
in | ||
match Topkg.cmd with | ||
| `Explain -> pr_explanation btool bdir pkg mvs | ||
| `Help -> pr_help () | ||
| `Build -> warn_unused (); build btool bdir pkg mvs | ||
end | ||
|
||
(*--------------------------------------------------------------------------- | ||
Copyright (c) 2014 Daniel C. Bünzli. | ||
All rights reserved. | ||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions | ||
are met: | ||
1. Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
2. 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. | ||
3. Neither the name of Daniel C. Bünzli nor the names of | ||
contributors may be used to endorse or promote products derived | ||
from this software without specific prior written permission. | ||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
---------------------------------------------------------------------------*) |
Oops, something went wrong.