pax_global_header 0000666 0000000 0000000 00000000064 14767105225 0014523 g ustar 00root root 0000000 0000000 52 comment=abb287e2df94221d3c47f1408afb96d318d5426f
camlp5-camlp5-buildscripts-abb287e/ 0000775 0000000 0000000 00000000000 14767105225 0017264 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/.github/ 0000775 0000000 0000000 00000000000 14767105225 0020624 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/.github/workflows/ 0000775 0000000 0000000 00000000000 14767105225 0022661 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/.github/workflows/ci-debug.yml 0000664 0000000 0000000 00000002715 14767105225 0025070 0 ustar 00root root 0000000 0000000 name: CI-DEBUG
# on: [push, pull_request]
on: [workflow_dispatch]
jobs:
build:
strategy:
fail-fast: false
# Test Linux, macOS and Windows with the oldest and newest supported OCaml
# and trunk.
matrix:
os:
# - macos-latest
# - ubuntu-latest
- windows-latest
ocaml-version:
# - "4.14"
- "5.3"
# include:
# - os: ubuntu-latest
# ocaml-version: "4.10"
# - os: macos-13
# ocaml-version: "4.10"
# - os: macos-latest
# ocaml-version: "4.10"
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set-up OCaml ${{ matrix.ocaml-version }}
uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: ${{ matrix.ocaml-version }}
- name: Setup Dependencies
run: |
opam install . --deps-only --with-doc --with-test
opam pin add camlp5-buildscripts . --no-action
- name: Build it with make
run: |
opam exec -- make sys
- name: Test it with make
run: |
opam exec -- make test
# opam exec -- make clean
- name: Install it with opam
run: |
opam install --strict camlp5-buildscripts
- name: Archive test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: test/*
camlp5-camlp5-buildscripts-abb287e/.github/workflows/ci.yml 0000664 0000000 0000000 00000002437 14767105225 0024005 0 ustar 00root root 0000000 0000000 name: CI
# on: [push, pull_request]
on: [workflow_dispatch]
jobs:
build:
strategy:
fail-fast: false
# Test Linux, macOS and Windows with the oldest and newest supported OCaml
# and trunk.
matrix:
os:
- macos-latest
- ubuntu-latest
- windows-latest
ocaml-version:
- "4.14"
- "5.3"
include:
- os: ubuntu-latest
ocaml-version: "4.10"
- os: macos-13
ocaml-version: "4.10"
- os: macos-latest
ocaml-version: "4.10"
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set-up OCaml ${{ matrix.ocaml-version }}
uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: ${{ matrix.ocaml-version }}
- name: Setup Dependencies
run: |
opam install . --deps-only --with-doc --with-test
opam pin add camlp5-buildscripts . --no-action
- name: Build it with make
run: |
opam exec -- make sys
- name: Test it with make
run: |
opam exec -- make test
opam exec -- make clean
- name: Install it with opam
run: |
opam install --strict camlp5-buildscripts
camlp5-camlp5-buildscripts-abb287e/.gitignore 0000664 0000000 0000000 00000000037 14767105225 0021254 0 ustar 00root root 0000000 0000000 *.cm*
local-install
*.bak
*.NEW camlp5-camlp5-buildscripts-abb287e/CHANGES 0000664 0000000 0000000 00000002570 14767105225 0020263 0 ustar 00root root 0000000 0000000 camlp5-buildscripts Version 0.06
--------------------------------
* [19 Mar 2025] Windows fixup: this time, fixing path-separator (thanks, @tobil4sk)
camlp5-buildscripts Version 0.05
--------------------------------
* [19 Mar 2025] more fixups to try to make this work on Windows
camlp5-buildscripts Version 0.04
-------------------
* [13 Dec 2024] tiny fixup for Makefile, to support Windows. Thanks to @tobil4sk for this!
camlp5-buildscripts Version 0.03
-------------------
* [22 Jul 2023] Stupid, stupid, stupid error in ya-wrap-ocamlfind (was ignoring return-code from invoked command)
This caused errors in builds in pa_ppx* packages to be silently ignored. Ugh. What idiocy. Fixed.
This means that older pa_ppx* packages cannot build with this package/version. But it's only b/c they
enable "debugging preprocessing" by default. If that's disabled, then they build fine. But still, what
a mess.
That this is such a tiny error is even more maddening.
camlp5-buildscripts Version 0.02
-------------------
* [30 Jan 2023] some small changes
ya-wrap-ocamlfind: change syntax of header comment to "(**pp ... *)"
join_meta: reverse order of subdirs for wrap-subdirs, so more comprehensible to invokers
all: change bootstrap to not generate static blocks, switch to pa_ppx_regexp
camlp5-buildscripts Version 0.01
-------------------
* [30 Jan 2023] First release
camlp5-camlp5-buildscripts-abb287e/LICENSE 0000664 0000000 0000000 00000002053 14767105225 0020271 0 ustar 00root root 0000000 0000000 MIT License
Copyright (c) 2023 chetmurthy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.
camlp5-camlp5-buildscripts-abb287e/Makefile 0000664 0000000 0000000 00000001204 14767105225 0020721 0 ustar 00root root 0000000 0000000
SYSDIRS= src
TESTDIRS= test
OCAMLFIND=ocamlfind
all: sys
set -e; for i in $(TESTDIRS); do cd $$i; $(MAKE) all; cd ..; done
sys:
set -e; for i in $(SYSDIRS); do cd $$i; $(MAKE) all; cd ..; done
test: all
set -e; for i in $(TESTDIRS); do cd $$i; $(MAKE) test; cd ..; done
bootstrap:
$(MAKE) -C pa_ppx_src bootstrap
install: all
$(OCAMLFIND) remove camlp5-buildscripts || true
$(OCAMLFIND) install camlp5-buildscripts local-install/lib/camlp5-buildscripts/*
uninstall:
$(OCAMLFIND) remove camlp5-buildscripts || true
clean::
set -e; for i in $(SYSDIRS) $(TESTDIRS); do cd $$i; $(MAKE) clean; cd ..; done
rm -rf docs local-install
camlp5-camlp5-buildscripts-abb287e/README.asciidoc 0000664 0000000 0000000 00000007524 14767105225 0021731 0 ustar 00root root 0000000 0000000 camlp5-buildscripts: Sysadmin scripts for Camlp5 projects
=========================================================
Sysadmin scripts written in OCaml (and Perl precursors), for use with
Camlp5 and Camlp5-based projects. These will allow removing
dependency on Perl for these projects.
== Invocation
The scripts are not installed in a bin-directory, but rather in the
package's directory. So to invoke, we use the ocamlfind "exe" syntax. For example, to invoke "fixin":
```
ocamlfind camlp5-buildscripts/fixin .... args ....
```
== The Scripts
`fixin`::
"fixes" the `#!` line of a script so that it points at an executable
on the current `PATH`. That is, if the #! line is
```
#!perl
```
then it will be rewritten to the full-path of the `perl` that is found
on the current `PATH`.
`join_meta`::
Joins up a bunch of `META` files into a single `META` file. The idea
is, you have a bunch of subdirectories, each of which installs a subpackage.
One of those subpackages might actually be the "main" package, and you
want the other subdirectories' META files to become subpackages in the
new META file you're constructing. And at the same time, you'll want
to rewrite names of those subpackages. For example, if your target
package is `pa_ppx_regexp`, and you have two subdirectories:
* `pa_perl` which installs a package `pa_ppx_regexp`
* `runtime` which installs a package `pa_ppx_regexp_runtime`
then you might want to build a composite `META` file that is based on
that of `pa_perl`, but has `runtime`'s `META` file as a subpackage,
named `"runtime"`. And then you'd want to replace all instances of
`pa_ppx_regexp_runtime` with `pa_ppx_regexp.runtime` (notice "_" changes
to ".") but only in `require` statements.
`join_meta` does the above. Its usage:
```
join_meta -destdir
-direct-include directly include /META file
-wrap-subdir : include /META file wrapped as subpackage
-rewrite : rewrite packages named to in `require' statements
-help Display this list of options
--help Display this list of options
```
It assumes that every subdirectory has a `META` file already-created,
and joins them up, outputing the result to stdout.
`ya-wrap-ocamlfind`::
"yet another ocamlfind wrapper". No doco yet.
`LAUNCH`::
`LAUNCH` assumes there is an environment variable `TOP` that is either
a relative or absolute reference to the top-level directory of the
current project. It adds `$(TOP)/local-install/bin` to the `PATH` and
sets `OCAMLPATH` to `$(TOP)/local-install/lib:` . This is useful for
running `ocamlfind` commands that use the `$(TOP)/local-install`
directory as a local installation-directory (hence no need to pollute
global install-directories with package installation during complex
multi-step builds. This means that when running tests (and multistep
builds), we can assume that already-built packages are "installed" and
can use `ocamlfind` to access them.
`LAUNCH` is invoked thus:
```
ocamlfind camlp5-buildscripts/LAUNCH -v --
```
Note that the `--` is mandatory.
== Maintenance
There are two directories containing these scripts: `pa_ppx_src` and
`src`. The former directory contains scripts that are written using
`pa_ppx_regexp` and whatever other PPX rewriters one might desire. The
latter directory contains those same scripts, but after expansion via
`not-ocamlfind preprocess` The "make all install" process only builds
the scripts in `src`, so PPX rewriters are not necessary to build and
install this project -- which is the point, so that this project can
be used as build-scripts in `camlp5` and various PPX rewriter
projects.
There is a "bootstrap" target in the toplevel that will update the
scripts in `src` if they are out-of-date w.r.t. the versions in
`pa_ppx_src`, but it should be a no-op unless being used by the
maintainer of this package.
camlp5-camlp5-buildscripts-abb287e/opam 0000664 0000000 0000000 00000002044 14767105225 0020143 0 ustar 00root root 0000000 0000000 version: "0.06"
synopsis: "Camlp5 Build scripts (written in OCaml)"
description:
"""
These are build-scripts that are helpful in building Camlp5 and packages based on Camlp5.
As such, they need to *not* depend on Camlp5. The command are *not* installed in a
bin-directory, but in the package-directory, hence invoked via the "ocamlfind package/exe"
method.
"""
opam-version: "2.0"
x-maintenance-intent: [ "(latest)" ]
maintainer: "Chet Murthy "
authors: ["Chet Murthy"]
homepage: "https://github.com/camlp5/camlp5-buildscripts"
license: "BSD-3-Clause"
bug-reports: "https://github.com/camlp5/camlp5-buildscripts/issues"
dev-repo: "git+https://github.com/camlp5/camlp5-buildscripts.git"
doc: "https://github.com/camlp5/camlp5-buildscripts/doc"
depends: [
"ocaml" { >= "4.10.0" }
"not-ocamlfind" { >= "0.01" }
"mdx" { with-test & >= "2.2.1" }
"fmt"
"re" { >= "1.10.4" }
"bos" { >= "0.2.1" }
]
build: [
[make "sys"]
[make "test"] {with-test}
]
install: [make "install"]
url {
src: ""
checksum: [
"sha512="
]
}
camlp5-camlp5-buildscripts-abb287e/pa_ppx_src/ 0000775 0000000 0000000 00000000000 14767105225 0021422 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/pa_ppx_src/LAUNCH.ml 0000664 0000000 0000000 00000003145 14767105225 0022731 0 ustar 00root root 0000000 0000000
open Rresult
open Bos
open Fpath
let push l x = (l := x :: !l)
let verbose = ref false ;;
let veryverbose = ref false ;;
let cmd = ref [] ;;
Arg.(parse [
"-v", (Set verbose),"verbose output"
; "-vv", Set veryverbose, "very verbose output"
; "--", (Rest (fun s -> cmd := !cmd @ [s])),"the command"
]
(fun s -> cmd := !cmd @ [s])
"LAUNCH [-v] [--] "
) ;;
let ( let* ) x f = Rresult.(>>=) x f
let main () =
let* top =
match OS.Env.var "TOP" with
Some v -> Ok v
| None -> Error (`Msg "LAUNCH: environment variable TOP *must* be set to use this wrapper") in
let path_var_separator = match Sys.os_type with
| "Unix" -> ":"
| _ -> ";"
in
let* path = OS.Env.req_var "PATH" in
let newpath = [%pattern {|${top}/local-install/bin${path_var_separator}${path}|}] in
let* () =
OS.Env.set_var "PATH" (Some newpath)
in
let newcamlpath = [%pattern {|${top}/local-install/lib${path_var_separator}|}] in
let* () = OS.Env.set_var "OCAMLPATH" (Some newcamlpath) in
match !cmd with
exe::_ ->
if !verbose then Fmt.(pf stderr "LAUNCH: command %a\n%!" (list ~sep:(const string " ") Dump.string) !cmd) ;
if !veryverbose then
Fmt.
(pf stderr "LAUNCH: env PATH=%a OCAMLPATH=%a %a\n%!"
Dump.string newpath
Dump.string newcamlpath
(list ~sep:(const string " ") Dump.string) !cmd);
Ok (Unix.execvp exe (Array.of_list !cmd))
| _ -> Error (`Msg "LAUNCH: at least one argument (the command-name) must be provided")
;;
try R.failwith_error_msg (main ())
with exc ->
Fmt.(pf stderr "%a\n%!" exn exc)
camlp5-camlp5-buildscripts-abb287e/pa_ppx_src/Makefile 0000664 0000000 0000000 00000000454 14767105225 0023065 0 ustar 00root root 0000000 0000000
NOT_OCAMLFIND=not-ocamlfind
bootstrap: ../src/join_meta.ml ../src/ya_wrap_ocamlfind.ml ../src/fixin.ml ../src/LAUNCH.ml
../src/%.ml: %.ml
$(NOT_OCAMLFIND) preprocess -package pa_ppx_regexp,camlp5.pr_o -ppopt -pa_ppx_regexp-nostatic -syntax camlp5o $< > $@.NEW && \
mv $@.NEW $@
.SUFFIXES: .ml
camlp5-camlp5-buildscripts-abb287e/pa_ppx_src/fixin.ml 0000664 0000000 0000000 00000003325 14767105225 0023074 0 ustar 00root root 0000000 0000000 (** -syntax camlp5o *)
let push l x = (l := x :: !l)
open Rresult
open Bos
let read_fully ifile =
OS.File.read ifile
let write_fully ~mode ofile txt =
OS.File.write ~mode ofile txt
let ( let* ) x f = Rresult.(>>=) x f
;;
let verbose = ref true ;;
let files = ref [] ;;
Arg.(parse [
"-s", (Arg.Clear verbose),
("silence verbosity")
]
(fun s -> push files s)
"fixin [-s] ")
;;
let path_var_separator = match Sys.os_type with
| "Unix" -> ':'
| _ -> ';'
let search_path =
let dirs = String.split_on_char path_var_separator (Sys.getenv "PATH") in
List.map Fpath.v dirs
let fix_interpreter ~f (exedir, exename) =
let open Fpath in
let exename = v exename in
let candidates = List.map (fun dir -> append dir exename) search_path in
match List.find_opt OS.File.is_executable candidates with
None ->
if !verbose then Fmt.(pf stderr "Can't find %a in PATH, %a unchanged\n%!" pp exename pp f) ;
to_string (append (v exedir) exename)
| Some v ->
if !verbose then Fmt.(pf stderr "Changing %a to %a\n%!" pp f pp v) ;
to_string v
let fixin_contents ~f txt =
let txt = [%subst {|^#!([\S]+/)?([\S]+)|} / {|"#!" ^ (fix_interpreter ~f ($1$, $2$))|} /s e] txt in
Ok txt
let fixin1 f =
let open Fpath in
let f = v f in
let newf = add_ext "NEW" f in
let bakf = add_ext "bak" f in
let* st = OS.Path.stat f in
let mode = st.Unix.st_perm in
let* contents = read_fully f in
let* contents = fixin_contents ~f contents in
let* () = write_fully ~mode newf contents in
let* () = OS.Path.move ~force:true f bakf in
let* () = OS.Path.move ~force:true newf f in
Ok ()
;;
!files
|> List.iter (fun f ->
fixin1 f |> R.failwith_error_msg
)
;;
camlp5-camlp5-buildscripts-abb287e/pa_ppx_src/join_meta.ml 0000664 0000000 0000000 00000004772 14767105225 0023733 0 ustar 00root root 0000000 0000000 (** -syntax camlp5o *)
open Rresult
open Bos
open Fpath
let read_fully ifile =
OS.File.read ifile
let ( let* ) x f = Rresult.(>>=) x f
;;
let push l x = (l := x :: !l)
let read_ic_fully ?(msg="") ?(channel=stdin) () =
let fd = Unix.descr_of_in_channel channel in
if Unix.isatty fd && msg <> "" then begin
Printf.printf "%s\n" msg ; flush stdout ;
end ;
let b = Buffer.create 23 in
let rec rrec () =
match try Some(input_char channel)
with End_of_file -> None with
None -> Buffer.contents b
| Some c -> Buffer.add_char b c ; rrec ()
in
rrec()
let pkgmap = ref []
let direct_include = ref ""
let wrap_subdirs = ref []
let split2 ~msg s =
match [%match {|^([^:]+):([^:]+)$|} / strings (!1,!2)] s with
Some (name, subdir) -> (name, subdir)
| _ -> failwith Fmt.(str "%s: invalid arg <<%s>>" msg s)
;;
Arg.(parse [
"-direct-include", (Arg.Set_string direct_include),
(" directly include /META file")
;"-wrap-subdir", (Arg.String (fun s -> push wrap_subdirs (split2 ~msg:"wrap-subdir" s))),
(": include /META file wrapped as subpackage ")
;"-rewrite", (Arg.String (fun s -> push pkgmap (split2 ~msg:"rewrite" s))),
(": rewrite packages named to in `require' statements")
]
(fun _ -> failwith "join_meta: no anonymous args supported")
"join_meta -destdir ")
;;
let indent n txt =
let pfx = String.make n ' ' in
[%subst {|^|} / {|${pfx}|} / g m] txt
let fix txt =
let l = [%split {|\s*,\s*|}] txt in
let f s =
match List.assoc s !pkgmap with
exception Not_found -> s
| v -> v in
let ol =
l
|> List.map (fun p ->
[%subst {|^([^.]+)|} / {| f $1$ |} / e] p
) in
String.concat "," ol
let fix0 txt =
[%subst {|"([^"]+)"|} / {| "\"" ^ fix($1$) ^ "\"" |} / e] txt
let fixdeps txt =
[%subst {|^(.*require.*)$|} / {| fix0($1$) |} / m g e] txt
let capturex (cmd, args) =
let channel = Unix.open_process_args_in cmd args in
let txt = read_ic_fully ~channel () in
close_in channel ;
txt
;;
if !direct_include <> "" then
print_string (indent 2 (fixdeps(R.failwith_error_msg (read_fully (v [%pattern {|./${!direct_include}/META|}])))))
;;
!wrap_subdirs
|> List.rev
|> List.iter (fun (name, subdir) ->
let txt = indent 2 (fixdeps(R.failwith_error_msg (read_fully (v [%pattern {|./${subdir}/META|}])))) in
print_string [%pattern {|
package "${name}" (
${txt}
)
|}]
)
;;
camlp5-camlp5-buildscripts-abb287e/pa_ppx_src/ya_wrap_ocamlfind.ml 0000664 0000000 0000000 00000002700 14767105225 0025431 0 ustar 00root root 0000000 0000000 (** -syntax camlp5o *)
let rec split_args cmd = function
| "--" :: files -> List.rev cmd, files
| [file] -> List.rev cmd, [file]
| arg :: args -> split_args (arg :: cmd) args
| [] -> failwith "please supply input arguments"
let split_args = split_args []
let envsubst s =
let envlookup vname =
match Sys.getenv_opt vname with
Some v -> v
| None -> failwith [%pattern {|ya_wrap_ocamlfind: environment variable <<${vname}>> not found|}] in
let f s1 s2 =
if s1 <> "" then envlookup s1
else if s2 <> "" then envlookup s2
else assert false in
[%subst {|(?:\$\(([^)]+)\)|\$\{([^}]+)\})|} / {| f $1$ $2$ |} / g e] s
let discover_args f =
let f' = open_in f in
let rec drec () =
let line1 = input_line f' in
match ([%match {|^\s+$|} / pred] line1,
[%match {|^#.*$|} / pred] line1,
[%match {|^\(\*\*pp (.*?)\*\)|} / strings !1] line1) with
| (true, _, _) -> drec ()
| (_, true, _) -> drec ()
| (_, _, None) -> ""
| (_, _, Some params) -> envsubst params in
let rv = drec () in
close_in f';
rv
let () =
let cmd, files =
Array.to_list Sys.argv |> List.tl |> split_args in
let cmd = Filename.quote_command (List.hd cmd) (List.tl cmd) in
List.iter (fun f ->
let extra = discover_args f in
let cmd = [%pattern {|${cmd} ${extra} ${f}|}] in
Printf.fprintf stderr "%s\n%!" cmd;
let rc = Sys.command cmd in
if rc <> 0 then exit rc
)
files
camlp5-camlp5-buildscripts-abb287e/src/ 0000775 0000000 0000000 00000000000 14767105225 0020053 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/src/.gitignore 0000664 0000000 0000000 00000000051 14767105225 0022037 0 ustar 00root root 0000000 0000000 fixin
join_meta
ya-wrap-ocamlfind
LAUNCH
camlp5-camlp5-buildscripts-abb287e/src/LAUNCH.PL 0000775 0000000 0000000 00000001277 14767105225 0021274 0 ustar 00root root 0000000 0000000 #!/usr/bin/env perl
use strict ;
use IPC::System::Simple qw(systemx runx capturex $EXITVAL);
use String::ShellQuote ;
use File::Basename;
our $verbose = 0 ;
{
my $wd = dirname(dirname($0)) ;
my $top = $ENV{'TOP'} || $wd;
my %newenv ;
$newenv{'PATH'} = "$top/local-install/bin:$ENV{'PATH'}" ;
$newenv{'OCAMLPATH'} = "$top/local-install/lib:" ;
local %ENV = (%ENV, %newenv) ;
v_systemx([0], [@ARGV]) ;
}
sub v_systemx {
croak( "v_systemx: must specify exit codes") unless (ref($_[0]) eq 'ARRAY') ;
my $codes = shift ;
my @cmd = @{ shift @_ } ;
my %args = @_ ;
print STDERR join(' ', map { shell_quote($_) } @cmd)."\n" if $main::verbose ;
return runx($codes, @cmd) ;
}
camlp5-camlp5-buildscripts-abb287e/src/LAUNCH.ml 0000664 0000000 0000000 00000003255 14767105225 0021364 0 ustar 00root root 0000000 0000000
open Rresult
open Bos
open Fpath
let push l x = l := x :: !l
let verbose = ref false
let veryverbose = ref false
let cmd = ref []
let _ =
Arg.
(parse
["-v", Set verbose, "verbose output";
"-vv", Set veryverbose, "very verbose output";
"--", Rest (fun s -> cmd := !cmd @ [s]), "the command"]
(fun s -> cmd := !cmd @ [s]) "LAUNCH [-v] [--] ")
let ( let* ) x f = Rresult.(>>=) x f
let main () =
let* top =
match OS.Env.var "TOP" with
Some v -> Ok v
| None ->
Error
(`Msg
"LAUNCH: environment variable TOP *must* be set to use this wrapper")
in
let path_var_separator =
match Sys.os_type with
"Unix" -> ":"
| _ -> ";"
in
let* path = OS.Env.req_var "PATH" in
let newpath =
String.concat "" [top; "/local-install/bin"; path_var_separator; ""; path]
in
let* () = OS.Env.set_var "PATH" (Some newpath) in
let newcamlpath =
String.concat "" [top; "/local-install/lib"; path_var_separator]
in
let* () = OS.Env.set_var "OCAMLPATH" (Some newcamlpath) in
match !cmd with
exe :: _ ->
if !verbose then
Fmt.
(pf stderr "LAUNCH: command %a\n%!"
(list ~sep:(const string " ") Dump.string) !cmd);
if !veryverbose then
Fmt.
(pf stderr "LAUNCH: env PATH=%a OCAMLPATH=%a %a\n%!" Dump.string
newpath Dump.string newcamlpath
(list ~sep:(const string " ") Dump.string) !cmd);
Ok (Unix.execvp exe (Array.of_list !cmd))
| _ ->
Error
(`Msg
"LAUNCH: at least one argument (the command-name) must be provided")
let _ =
try R.failwith_error_msg (main ()) with
exc -> Fmt.(pf stderr "%a\n%!" exn exc)
camlp5-camlp5-buildscripts-abb287e/src/Makefile 0000664 0000000 0000000 00000001627 14767105225 0021521 0 ustar 00root root 0000000 0000000 ifeq ($(OS),Windows_NT)
WD=$(shell cygpath --absolute --windows .)
EXE=.exe
else
WD=$(shell pwd)
EXE=
endif
TOP=..
NOT_OCAMLFIND=not-ocamlfind
OCAMLFIND=ocamlfind
PACKAGES=re,fmt,unix,bos
BIN=ya-wrap-ocamlfind$(EXE) fixin$(EXE) join_meta$(EXE) LAUNCH$(EXE)
all: $(BIN)
$(MAKE) DESTDIR=$(WD)/$(TOP)/local-install/ install
ya-wrap-ocamlfind$(EXE): ya_wrap_ocamlfind.ml
$(OCAMLFIND) ocamlc -linkpkg -linkall -package $(PACKAGES) $< -o $@
join_meta$(EXE): join_meta.ml
$(OCAMLFIND) ocamlc -linkpkg -linkall -package $(PACKAGES) $< -o $@
fixin$(EXE): fixin.ml
$(OCAMLFIND) ocamlc -linkpkg -linkall -package $(PACKAGES) $< -o $@
LAUNCH$(EXE): LAUNCH.ml
$(OCAMLFIND) ocamlc -linkpkg -linkall -package $(PACKAGES) $< -o $@
install::
mkdir -p $(DESTDIR)/lib
touch META
$(NOT_OCAMLFIND) reinstall-if-diff camlp5-buildscripts -destdir $(DESTDIR)/lib META $(BIN)
rm -f META
clean::
rm -f *.bak *.cm* $(BIN) META
camlp5-camlp5-buildscripts-abb287e/src/fixin.PL 0000775 0000000 0000000 00000003726 14767105225 0021440 0 ustar 00root root 0000000 0000000 #!/usr/bin/perl
# Usage: fixin [-s] [files]
# Configuration constants.
$does_shbang = 1; # Does kernel recognize #! hack?
$verbose = 1; # Default to verbose
# Construct list of directories to search.
@absdirs = reverse grep(m!^/!, split(/:/, $ENV{'PATH'}, 999));
# Process command line arguments.
if ($ARGV[0] eq '-s') {
shift;
$verbose = 0;
}
die "Usage: fixin [-s] [files]\n" unless @ARGV || !-t;
@ARGV = '-' unless @ARGV;
# Now do each file.
FILE: foreach $filename (@ARGV) {
open(IN, $filename) ||
((warn "Can't process $filename: $!\n"), next);
$_ = ;
next FILE unless /^#!/; # Not a shbang file.
# Now figure out the interpreter name.
chop($cmd = $_);
$cmd =~ s/^#! *//;
($cmd,$arg) = split(' ', $cmd, 2);
$cmd =~ s!^.*/!!;
# Now look (in reverse) for interpreter in absolute PATH.
$found = '';
foreach $dir (@absdirs) {
if (-x "$dir/$cmd") {
warn "Ignoring $found\n" if $verbose && $found;
$found = "$dir/$cmd";
}
}
# Figure out how to invoke interpreter on this machine.
if ($found) {
warn "Changing $filename to $found\n" if $verbose;
if ($does_shbang) {
$_ = "#!$found";
$_ .= ' ' . $arg if $arg ne '';
$_ .= "\n";
}
else {
$_ = <$filename")
|| die "Can't create new $filename: $!\n";
($dev,$ino,$mode) = stat IN;
$mode = 0755 unless $dev;
chmod $mode, $filename;
select(OUT);
}
# Print out the new #! line (or equivalent).
print;
# Copy the rest of the file.
while () {
print;
}
close IN;
close OUT;
}
camlp5-camlp5-buildscripts-abb287e/src/fixin.ml 0000664 0000000 0000000 00000003730 14767105225 0021525 0 ustar 00root root 0000000 0000000 (** -syntax camlp5o *)
let push l x = l := x :: !l
open Rresult
open Bos
let read_fully ifile = OS.File.read ifile
let write_fully ~mode ofile txt = OS.File.write ~mode ofile txt
let ( let* ) x f = Rresult.(>>=) x f
let verbose = ref true
let files = ref []
let _ =
Arg.
(parse ["-s", Arg.Clear verbose, "silence verbosity"]
(fun s -> push files s) "fixin [-s] ")
let path_var_separator =
match Sys.os_type with
"Unix" -> ':'
| _ -> ';'
let search_path =
let dirs = String.split_on_char path_var_separator (Sys.getenv "PATH") in
List.map Fpath.v dirs
let fix_interpreter ~f (exedir, exename) =
let open Fpath in
let exename = v exename in
let candidates = List.map (fun dir -> append dir exename) search_path in
match List.find_opt OS.File.is_executable candidates with
None ->
if !verbose then
Fmt.
(pf stderr "Can't find %a in PATH, %a unchanged\n%!" pp exename pp f);
to_string (append (v exedir) exename)
| Some v ->
if !verbose then Fmt.(pf stderr "Changing %a to %a\n%!" pp f pp v);
to_string v
let fixin_contents ~f txt =
let txt =
Re.replace ~all:false
(Re.Perl.compile_pat ~opts:[`Dotall] "^#!([\\S]+/)?([\\S]+)")
~f:(fun __g__ ->
"#!" ^
fix_interpreter ~f
((match Re.Group.get_opt __g__ 1 with
None -> ""
| Some s -> s),
(match Re.Group.get_opt __g__ 2 with
None -> ""
| Some s -> s)))
txt
in
Ok txt
let fixin1 f =
let open Fpath in
let f = v f in
let newf = add_ext "NEW" f in
let bakf = add_ext "bak" f in
let* st = OS.Path.stat f in
let mode = st.Unix.st_perm in
let* contents = read_fully f in
let* contents = fixin_contents ~f contents in
let* () = write_fully ~mode newf contents in
let* () = OS.Path.move ~force:true f bakf in
let* () = OS.Path.move ~force:true newf f in Ok ()
let _ = !files |> List.iter (fun f -> fixin1 f |> R.failwith_error_msg)
camlp5-camlp5-buildscripts-abb287e/src/join_meta.ml 0000664 0000000 0000000 00000007154 14767105225 0022361 0 ustar 00root root 0000000 0000000 (** -syntax camlp5o *)
open Rresult
open Bos
open Fpath
let read_fully ifile = OS.File.read ifile
let ( let* ) x f = Rresult.(>>=) x f
let push l x = l := x :: !l
let read_ic_fully ?(msg = "") ?(channel = stdin) () =
let fd = Unix.descr_of_in_channel channel in
if Unix.isatty fd && msg <> "" then
begin Printf.printf "%s\n" msg; flush stdout end;
let b = Buffer.create 23 in
let rec rrec () =
match try Some (input_char channel) with End_of_file -> None with
None -> Buffer.contents b
| Some c -> Buffer.add_char b c; rrec ()
in
rrec ()
let pkgmap = ref []
let direct_include = ref ""
let wrap_subdirs = ref []
let split2 ~msg s =
match
(let __re__ = Re.Perl.compile_pat ~opts:[] "^([^:]+):([^:]+)$" in
fun __subj__ ->
match
Option.map (fun __g__ -> Re.Group.get __g__ 1, Re.Group.get __g__ 2)
(Re.exec_opt __re__ __subj__)
with
exception Not_found -> None
| rv -> rv)
s
with
Some (name, subdir) -> name, subdir
| _ -> failwith Fmt.(str "%s: invalid arg <<%s>>" msg s)
let _ =
Arg.
(parse
["-direct-include", Arg.Set_string direct_include,
" directly include /META file";
"-wrap-subdir",
Arg.String (fun s -> push wrap_subdirs (split2 ~msg:"wrap-subdir" s)),
": include /META file wrapped as subpackage ";
"-rewrite", Arg.String (fun s -> push pkgmap (split2 ~msg:"rewrite" s)),
": rewrite packages named to in `require' statements"]
(fun _ -> failwith "join_meta: no anonymous args supported")
"join_meta -destdir ")
let indent n txt =
let pfx = String.make n ' ' in
Re.replace ~all:true (Re.Perl.compile_pat ~opts:[`Multiline] "^")
~f:(fun __g__ -> String.concat "" [pfx]) txt
let fix txt =
let l =
(let __re__ = Re.Perl.compile_pat ~opts:[] "\\s*,\\s*" in
fun __subj__ -> Re.split __re__ __subj__)
txt
in
let f s =
match List.assoc s !pkgmap with
exception Not_found -> s
| v -> v
in
let ol =
l |>
List.map
(fun p ->
Re.replace ~all:false (Re.Perl.compile_pat ~opts:[] "^([^.]+)")
~f:(fun __g__ ->
f
(match Re.Group.get_opt __g__ 1 with
None -> ""
| Some s -> s))
p)
in
String.concat "," ol
let fix0 txt =
Re.replace ~all:false (Re.Perl.compile_pat ~opts:[] "\"([^\"]+)\"")
~f:(fun __g__ ->
"\"" ^
fix
(match Re.Group.get_opt __g__ 1 with
None -> ""
| Some s -> s) ^
"\"")
txt
let fixdeps txt =
Re.replace ~all:true
(Re.Perl.compile_pat ~opts:[`Multiline] "^(.*require.*)$")
~f:(fun __g__ ->
fix0
(match Re.Group.get_opt __g__ 1 with
None -> ""
| Some s -> s))
txt
let capturex (cmd, args) =
let channel = Unix.open_process_args_in cmd args in
let txt = read_ic_fully ~channel () in close_in channel; txt
let _ =
if !direct_include <> "" then
print_string
(indent 2
(fixdeps
(R.failwith_error_msg
(read_fully
(v (String.concat "" ["./"; !direct_include; "/META"]))))))
let _ =
(!wrap_subdirs |> List.rev) |>
List.iter
(fun (name, subdir) ->
let txt =
indent 2
(fixdeps
(R.failwith_error_msg
(read_fully
(v (String.concat "" ["./"; subdir; "/META"])))))
in
print_string
(String.concat "" ["\npackage \""; name; "\" (\n"; txt; "\n)\n"]))
camlp5-camlp5-buildscripts-abb287e/src/ya-wrap-ocamlfind.PL 0000775 0000000 0000000 00000001644 14767105225 0023632 0 ustar 00root root 0000000 0000000 #!/usr/bin/env perl
use strict ;
use String::ShellQuote ;
our @cmd ;
our @files ;
while (@ARGV) {
if ($ARGV[0] eq "--") { shift @ARGV ; @files = @ARGV ; last ; }
elsif (int(@ARGV) == 1) {
@files = @ARGV ;
last ;
}
else { push(@cmd, shift @ARGV) ; }
}
{
@cmd = map { shell_quote($_) } @cmd ;
foreach my $f (@files) {
my $extra = discover_args($f) ;
my $cmd = "@cmd $extra $f\n" ;
print STDERR $cmd ;
system($cmd) ;
}
}
sub discover_args {
my $f = shift ;
open(F, "<$f") || die "$0: cannot open $f for read (to sense extra args)" ;
my $line1 = ;
close(F) ;
if ($line1 =~ m,^\(\*\*(.*?)\*\),) {
my $extra = $1 ;
$extra =~ s/(?:\$\(([^)]+)\)|\$\{([^}]+)\})/ envsubst($1, $2) /ge ;
return $extra ;
}
else {
return "" ;
}
}
sub envsubst {
my $varna = shift ;
die "env var $varna is not set"
unless exists $ENV{$varna} ;
return $ENV{$varna} ;
}
camlp5-camlp5-buildscripts-abb287e/src/ya_wrap_ocamlfind.ml 0000664 0000000 0000000 00000004217 14767105225 0024067 0 ustar 00root root 0000000 0000000 (** -syntax camlp5o *)
let rec split_args cmd =
function
"--" :: files -> List.rev cmd, files
| [file] -> List.rev cmd, [file]
| arg :: args -> split_args (arg :: cmd) args
| [] -> failwith "please supply input arguments"
let split_args = split_args []
let envsubst s =
let envlookup vname =
match Sys.getenv_opt vname with
Some v -> v
| None ->
failwith
(String.concat ""
["ya_wrap_ocamlfind: environment variable <<"; vname;
">> not found"])
in
let f s1 s2 =
if s1 <> "" then envlookup s1
else if s2 <> "" then envlookup s2
else assert false
in
Re.replace ~all:true
(Re.Perl.compile_pat ~opts:[] "(?:\\$\\(([^)]+)\\)|\\$\\{([^}]+)\\})")
~f:(fun __g__ ->
f
(match Re.Group.get_opt __g__ 1 with
None -> ""
| Some s -> s)
(match Re.Group.get_opt __g__ 2 with
None -> ""
| Some s -> s))
s
let discover_args f =
let f' = open_in f in
let rec drec () =
let line1 = input_line f' in
match
(let __re__ = Re.Perl.compile_pat ~opts:[] "^\\s+$" in
fun __subj__ -> Re.execp __re__ __subj__)
line1,
(let __re__ = Re.Perl.compile_pat ~opts:[] "^#.*$" in
fun __subj__ -> Re.execp __re__ __subj__)
line1,
(let __re__ = Re.Perl.compile_pat ~opts:[] "^\\(\\*\\*pp (.*?)\\*\\)" in
fun __subj__ ->
match
Option.map (fun __g__ -> Re.Group.get __g__ 1)
(Re.exec_opt __re__ __subj__)
with
exception Not_found -> None
| rv -> rv)
line1
with
true, _, _ -> drec ()
| _, true, _ -> drec ()
| _, _, None -> ""
| _, _, Some params -> envsubst params
in
let rv = drec () in close_in f'; rv
let () =
let (cmd, files) = (Array.to_list Sys.argv |> List.tl) |> split_args in
let cmd = Filename.quote_command (List.hd cmd) (List.tl cmd) in
List.iter
(fun f ->
let extra = discover_args f in
let cmd = String.concat "" [cmd; " "; extra; " "; f] in
Printf.fprintf stderr "%s\n%!" cmd;
let rc = Sys.command cmd in if rc <> 0 then exit rc)
files
camlp5-camlp5-buildscripts-abb287e/test/ 0000775 0000000 0000000 00000000000 14767105225 0020243 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/test/.gitignore 0000664 0000000 0000000 00000000023 14767105225 0022226 0 ustar 00root root 0000000 0000000 _build
*.corrected
camlp5-camlp5-buildscripts-abb287e/test/LAUNCH.md 0000664 0000000 0000000 00000000244 14767105225 0021537 0 ustar 00root root 0000000 0000000 ```sh
$ ../src/LAUNCH echo foo
Failure("LAUNCH: environment variable TOP *must* be set to use this wrapper")
```
```sh
$ env TOP=.. ../src/LAUNCH echo foo
foo
```
camlp5-camlp5-buildscripts-abb287e/test/Makefile 0000664 0000000 0000000 00000000315 14767105225 0021702 0 ustar 00root root 0000000 0000000
TESTS=LAUNCH join_meta ya-wrap-ocamlfind
all:
test: $(TESTS)
%: %.md
rm -f $<.corrected
ocaml-mdx test $<
test '!' -f $<.corrected || diff -I '```' -Bwiu $< $<.corrected
clean::
rm -f *.corrected
camlp5-camlp5-buildscripts-abb287e/test/join_meta.md 0000664 0000000 0000000 00000002420 14767105225 0022530 0 ustar 00root root 0000000 0000000 ```sh
$ ../src/join_meta -rewrite pa_ppx_regexp_runtime:pa_ppx_regexp.runtime -direct-include t/join_meta/pa_perl -wrap-subdir runtime:t/join_meta/runtime
# Specifications for the "pa_ppx_regexp" preprocessor:
requires = "camlp5,fmt,re,pa_ppx.base,pa_ppx_regexp.runtime,camlp5.parser_quotations"
version = "0.01"
description = "pa_ppx_regexp: pa_ppx_regexp rewriter"
# For linking
package "link" (
requires = "camlp5,fmt,re,pa_ppx.base.link,camlp5.parser_quotations.link"
archive(byte) = "pa_ppx_regexp.cma"
archive(native) = "pa_ppx_regexp.cmxa"
)
# For the toploop:
archive(byte,toploop) = "pa_ppx_regexp.cma"
# For the preprocessor itself:
requires(syntax,preprocessor) = "camlp5,fmt,re,pa_ppx.base,camlp5.parser_quotations"
archive(syntax,preprocessor,-native) = "pa_ppx_regexp.cma"
archive(syntax,preprocessor,native) = "pa_ppx_regexp.cmxa"
package "runtime" (
# Specifications for the "pa_ppx_regexp_runtime" package:
requires = "fmt"
version = "0.01"
description = "pa_ppx_regexp runtime support"
# For linking
archive(byte) = "pa_ppx_regexp_runtime.cma"
archive(native) = "pa_ppx_regexp_runtime.cmxa"
# For the toploop:
archive(byte,toploop) = "pa_ppx_regexp_runtime.cma"
)
```
camlp5-camlp5-buildscripts-abb287e/test/t/ 0000775 0000000 0000000 00000000000 14767105225 0020506 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/test/t/join_meta/ 0000775 0000000 0000000 00000000000 14767105225 0022453 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/test/t/join_meta/pa_perl/ 0000775 0000000 0000000 00000000000 14767105225 0024075 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/test/t/join_meta/pa_perl/META 0000664 0000000 0000000 00000001300 14767105225 0024540 0 ustar 00root root 0000000 0000000
# Specifications for the "pa_ppx_regexp" preprocessor:
requires = "camlp5,fmt,re,pa_ppx.base,pa_ppx_regexp_runtime,camlp5.parser_quotations"
version = "0.01"
description = "pa_ppx_regexp: pa_ppx_regexp rewriter"
# For linking
package "link" (
requires = "camlp5,fmt,re,pa_ppx.base.link,camlp5.parser_quotations.link"
archive(byte) = "pa_ppx_regexp.cma"
archive(native) = "pa_ppx_regexp.cmxa"
)
# For the toploop:
archive(byte,toploop) = "pa_ppx_regexp.cma"
# For the preprocessor itself:
requires(syntax,preprocessor) = "camlp5,fmt,re,pa_ppx.base,camlp5.parser_quotations"
archive(syntax,preprocessor,-native) = "pa_ppx_regexp.cma"
archive(syntax,preprocessor,native) = "pa_ppx_regexp.cmxa"
camlp5-camlp5-buildscripts-abb287e/test/t/join_meta/pa_ppx_regexp_runtime/ 0000775 0000000 0000000 00000000000 14767105225 0027057 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/test/t/join_meta/pa_ppx_regexp_runtime/META 0000664 0000000 0000000 00000000476 14767105225 0027537 0 ustar 00root root 0000000 0000000
# Specifications for the "pa_ppx_regexp_runtime" package:
requires = "fmt"
version = "0.01"
description = "pa_ppx_regexp runtime support"
# For linking
archive(byte) = "pa_ppx_regexp_runtime.cma"
archive(native) = "pa_ppx_regexp_runtime.cmxa"
# For the toploop:
archive(byte,toploop) = "pa_ppx_regexp_runtime.cma"
camlp5-camlp5-buildscripts-abb287e/test/t/join_meta/runtime/ 0000775 0000000 0000000 00000000000 14767105225 0024136 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/test/t/join_meta/runtime/META 0000664 0000000 0000000 00000000476 14767105225 0024616 0 ustar 00root root 0000000 0000000
# Specifications for the "pa_ppx_regexp_runtime" package:
requires = "fmt"
version = "0.01"
description = "pa_ppx_regexp runtime support"
# For linking
archive(byte) = "pa_ppx_regexp_runtime.cma"
archive(native) = "pa_ppx_regexp_runtime.cmxa"
# For the toploop:
archive(byte,toploop) = "pa_ppx_regexp_runtime.cma"
camlp5-camlp5-buildscripts-abb287e/test/t/ya-wrap-ocamlfind/ 0000775 0000000 0000000 00000000000 14767105225 0024020 5 ustar 00root root 0000000 0000000 camlp5-camlp5-buildscripts-abb287e/test/t/ya-wrap-ocamlfind/after-cppo.ml 0000664 0000000 0000000 00000000175 14767105225 0026415 0 ustar 00root root 0000000 0000000 # 1 "test_utils.ml"
(**pp -syntax camlp5o -package $(PAPACKAGES) *)
(* Copyright 2019 Chetan Murthy, All rights reserved. *)
camlp5-camlp5-buildscripts-abb287e/test/t/ya-wrap-ocamlfind/before-cppo.ml 0000664 0000000 0000000 00000000244 14767105225 0026553 0 ustar 00root root 0000000 0000000 #ifdef PAPPX
(**pp -syntax camlp5o -package $(PAPACKAGES) *)
#else
(**pp -package $(PPXPACKAGES) *)
#endif
(* Copyright 2019 Chetan Murthy, All rights reserved. *)
camlp5-camlp5-buildscripts-abb287e/test/t/ya-wrap-ocamlfind/simple.ml 0000664 0000000 0000000 00000000042 14767105225 0025637 0 ustar 00root root 0000000 0000000 (**pp -syntax goober *)
let x = 1
camlp5-camlp5-buildscripts-abb287e/test/t/ya-wrap-ocamlfind/use_str.ml 0000664 0000000 0000000 00000000072 14767105225 0026035 0 ustar 00root root 0000000 0000000 (**pp -package str *)
open Str
let re = Str.regexp "foo"
camlp5-camlp5-buildscripts-abb287e/test/ya-wrap-ocamlfind.md 0000664 0000000 0000000 00000004146 14767105225 0024104 0 ustar 00root root 0000000 0000000 ```sh
$ ../src/ya-wrap-ocamlfind echo t/ya-wrap-ocamlfind/simple.ml
'echo' -syntax goober t/ya-wrap-ocamlfind/simple.ml
-syntax goober t/ya-wrap-ocamlfind/simple.ml
```
```sh
$ rm -f t/ya-wrap-ocamlfind/use_str.cm*
$ ../src/ya-wrap-ocamlfind ocamlfind ocamlc -c t/ya-wrap-ocamlfind/use_str.ml
'ocamlfind' 'ocamlc' '-c' -package str t/ya-wrap-ocamlfind/use_str.ml
$ ls t/ya-wrap-ocamlfind/use_str.cm*
t/ya-wrap-ocamlfind/use_str.cmi
t/ya-wrap-ocamlfind/use_str.cmo
```
```sh
$ rm -f t/ya-wrap-ocamlfind/use_str.cm*
$ TOP=.. ../src/LAUNCH -v -- ../src/ya-wrap-ocamlfind ocamlfind ocamlc -c t/ya-wrap-ocamlfind/use_str.ml
LAUNCH: command "../src/ya-wrap-ocamlfind" "ocamlfind" "ocamlc" "-c" "t/ya-wrap-ocamlfind/use_str.ml"
'ocamlfind' 'ocamlc' '-c' -package str t/ya-wrap-ocamlfind/use_str.ml
$ ls t/ya-wrap-ocamlfind/use_str.cm*
t/ya-wrap-ocamlfind/use_str.cmi
t/ya-wrap-ocamlfind/use_str.cmo
```
```sh
$ PAPACKAGES=foo,bar ../src/ya-wrap-ocamlfind echo t/ya-wrap-ocamlfind/after-cppo.ml
'echo' -syntax camlp5o -package foo,bar t/ya-wrap-ocamlfind/after-cppo.ml
-syntax camlp5o -package foo,bar t/ya-wrap-ocamlfind/after-cppo.ml
```
```sh
$ rm -rf _build && mkdir -p _build
```
```sh
$ cppo -D PAPPX t/ya-wrap-ocamlfind/before-cppo.ml > _build/cppo.pappx.ml
$ PAPACKAGES=foo,bar PPXPACKAGES=buzz,fuzz ../src/ya-wrap-ocamlfind echo _build/cppo.pappx.ml
'echo' -syntax camlp5o -package foo,bar _build/cppo.pappx.ml
-syntax camlp5o -package foo,bar _build/cppo.pappx.ml
$ cat _build/cppo.pappx.ml
# 2 "t/ya-wrap-ocamlfind/before-cppo.ml"
(**pp -syntax camlp5o -package $(PAPACKAGES) *)
# 6 "t/ya-wrap-ocamlfind/before-cppo.ml"
(* Copyright 2019 Chetan Murthy, All rights reserved. *)
```
```sh
$ cppo -U PAPPX t/ya-wrap-ocamlfind/before-cppo.ml > _build/cppo.ppx.ml
$ PAPACKAGES=foo,bar PPXPACKAGES=buzz,fuzz ../src/ya-wrap-ocamlfind echo _build/cppo.ppx.ml
'echo' -package buzz,fuzz _build/cppo.ppx.ml
-package buzz,fuzz _build/cppo.ppx.ml
$ cat _build/cppo.ppx.ml
# 4 "t/ya-wrap-ocamlfind/before-cppo.ml"
(**pp -package $(PPXPACKAGES) *)
# 6 "t/ya-wrap-ocamlfind/before-cppo.ml"
(* Copyright 2019 Chetan Murthy, All rights reserved. *)
```