This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
|
|
@ -0,0 +1,34 @@
|
|||
----------------------------------------------------------------------------------
|
||||
* (foreign_library ...) is unavailable before Dune 2.0.
|
||||
|
||||
$ echo "(lang dune 1.0)" > dune-project
|
||||
$ mkdir -p lib
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (language c)
|
||||
> (names add))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "lib/dune", lines 1-3, characters 0-44:
|
||||
1 | (foreign_library
|
||||
2 | (language c)
|
||||
3 | (names add))
|
||||
Error: 'foreign_library' is only available since version 2.0 of the dune
|
||||
language. Please update your dune-project file to have (lang dune 2.0).
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* (foreign_library ...) is available in Dune 2.0.
|
||||
* "archive_name" is a required field.
|
||||
|
||||
$ echo "(lang dune 2.0)" > dune-project
|
||||
|
||||
$ dune build
|
||||
File "lib/dune", lines 1-3, characters 0-44:
|
||||
1 | (foreign_library
|
||||
2 | (language c)
|
||||
3 | (names add))
|
||||
Error: Field "archive_name" is missing
|
||||
[1]
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
Test the `byte_complete` executable mode
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 2.2)
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name foo)
|
||||
> (modules foo)
|
||||
> (foreign_stubs
|
||||
> (language c)
|
||||
> (names stub)))
|
||||
> (executable
|
||||
> (name prog)
|
||||
> (modules prog)
|
||||
> (libraries foo)
|
||||
> (modes byte byte_complete))
|
||||
> EOF
|
||||
|
||||
$ cat >stub.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> #include <caml/alloc.h>
|
||||
> CAMLprim value foo() {
|
||||
> return caml_copy_string("OCaml, plus fort que le segfault!");
|
||||
> }
|
||||
> EOF
|
||||
|
||||
$ echo 'external foo : unit -> string = "foo"' > foo.ml
|
||||
$ echo 'print_endline (Foo.foo ())' > prog.ml
|
||||
|
||||
$ dune build
|
||||
|
||||
The stubs are not present in the .bc:
|
||||
|
||||
$ grep -q 'OCaml, plus fort que le segfault!' _build/default/prog.bc
|
||||
[1]
|
||||
|
||||
But they are in the .bc.exe:
|
||||
|
||||
$ grep -q 'OCaml, plus fort que le segfault!' _build/default/prog.bc.exe
|
||||
|
|
@ -0,0 +1 @@
|
|||
(lang dune 3.5)
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
This test won't work with MSVC as it's using GCC and clang CLI
|
||||
parameters.
|
||||
|
||||
The flag should be present in the command, as we want it in the
|
||||
:standard set.
|
||||
|
||||
We don't actually test that the compiler outputs colors, just that
|
||||
Dune correctly passes the flag when required, and doesn't when it's
|
||||
not.
|
||||
|
||||
test that we pass the flag
|
||||
==========================
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name test)
|
||||
> (foreign_stubs (language c) (names stub)))
|
||||
> EOF
|
||||
|
||||
$ dune rules -m stub.o | grep -ce "-fdiagnostics-color=always"
|
||||
1
|
||||
|
||||
test color flag disabled
|
||||
========================
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name test)
|
||||
> (foreign_stubs
|
||||
> (flags :standard \ -fdiagnostics-color=always)
|
||||
> (language c) (names stub)))
|
||||
> EOF
|
||||
|
||||
$ dune rules -m stub.o | grep -ce "-fdiagnostics-color=always"
|
||||
0
|
||||
[1]
|
||||
|
||||
test that we correctly filter out the color codes
|
||||
=================================================
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name test)
|
||||
> (foreign_stubs
|
||||
> (language c) (names stub)))
|
||||
> EOF
|
||||
|
||||
We check there is no ESC [ sequence.
|
||||
|
||||
$ dune build 2>&1 | grep `printf '\033\\['`
|
||||
[1]
|
||||
|
|
@ -0,0 +1 @@
|
|||
#error "error message"
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
(library
|
||||
(name test)
|
||||
(foreign_stubs (language c) (names foo))
|
||||
(foreign_stubs (language c) (names bar) (flags)))
|
||||
|
||||
(vendored_dirs vendor)
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
Prior to dune 2.8 ocamlc_cflags and ocamlc_cppflags where
|
||||
always prepended to the C compiler command line
|
||||
|
||||
In the following tests, foo.c is built with the :standard set of flags while
|
||||
bar.c is built with an "empty" set of flags.
|
||||
|
||||
$ O_CC=$(ocamlc -config-var c_compiler)
|
||||
$ O_CFLAGS=$(ocamlc -config-var ocamlc_cflags)
|
||||
$ O_CPPFLAGS=$(ocamlc -config-var ocamlc_cppflags)
|
||||
$ O_CC=$(echo $O_CC | sed -e 's/^[[:blank:]]*//')
|
||||
$ O_CFLAGS=$(echo $O_CFLAGS | sed -e 's/^[[:blank:]]*//')
|
||||
$ O_CPPFLAGS=$(echo $O_CPPFLAGS | sed -e 's/^[[:blank:]]*//')
|
||||
|
||||
|
||||
|
||||
use_standard_c_and_cxx_flags = default (false)
|
||||
==================================
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 2.8)
|
||||
> EOF
|
||||
|
||||
$ dune rules -m foo.o | tr -s '\t\n\\' ' ' > out_foo
|
||||
File "dune", line 4, characters 36-39:
|
||||
4 | (foreign_stubs (language c) (names bar) (flags)))
|
||||
^^^
|
||||
Warning: The flag set for these foreign sources overrides the `:standard` set
|
||||
of flags. However the flags in this standard set are still added to the
|
||||
compiler arguments by Dune. This might cause unexpected issues. You can
|
||||
disable this warning by defining the option `(use_standard_c_and_cxx_flags
|
||||
<bool>)` in your `dune-project` file. Setting this option to `true` will
|
||||
effectively prevent Dune from silently adding c-flags to the compiler
|
||||
arguments which is the new recommended behaviour.
|
||||
|
||||
$ dune rules -m bar.o | tr -s '\t\n\\' ' ' > out_bar
|
||||
File "dune", line 4, characters 36-39:
|
||||
4 | (foreign_stubs (language c) (names bar) (flags)))
|
||||
^^^
|
||||
Warning: The flag set for these foreign sources overrides the `:standard` set
|
||||
of flags. However the flags in this standard set are still added to the
|
||||
compiler arguments by Dune. This might cause unexpected issues. You can
|
||||
disable this warning by defining the option `(use_standard_c_and_cxx_flags
|
||||
<bool>)` in your `dune-project` file. Setting this option to `true` will
|
||||
effectively prevent Dune from silently adding c-flags to the compiler
|
||||
arguments which is the new recommended behaviour.
|
||||
|
||||
No warning in vendored subfolder
|
||||
|
||||
$ dune build vendor/barv.o
|
||||
|
||||
Ocamlc_cflags are duplicated if the :standard set is kept:
|
||||
$ cat out_foo | grep -ce "${O_CFLAGS} ${O_CPPFLAGS} ${O_CFLAGS}"
|
||||
1
|
||||
|
||||
Whether or not the :standard flags is overridden, both ocamlc_cflags and
|
||||
ocamlc_cpp flags appear in the compiler command line:
|
||||
|
||||
$ cat out_foo | grep -ce "${O_CFLAGS} ${O_CPPFLAGS}"
|
||||
1
|
||||
|
||||
$ cat out_bar | grep -ce "${O_CFLAGS} ${O_CPPFLAGS}"
|
||||
1
|
||||
|
||||
use_standard_c_and_cxx_flags = true
|
||||
=================================
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 2.8)
|
||||
> (use_standard_c_and_cxx_flags true)
|
||||
> EOF
|
||||
|
||||
$ dune rules -m foo.o | tr -s '\t\n\\' ' ' > out_foo
|
||||
$ dune rules -m bar.o | tr -s '\t\n\\' ' ' > out_bar
|
||||
|
||||
Ocamlc_cflags are not duplicated anymore:
|
||||
$ cat out_foo | grep -ce "${O_CFLAGS} ${O_CPPFLAGS} ${O_CFLAGS}"
|
||||
0
|
||||
[1]
|
||||
|
||||
When the :standard flags is overridden, ocamlc_cflags and
|
||||
ocamlc_cpp are effectively removed from the compiler command line
|
||||
|
||||
$ cat out_foo | grep -ce "${O_CFLAGS} ${O_CPPFLAGS}"
|
||||
1
|
||||
|
||||
$ cat out_bar | grep -ce "${O_CFLAGS}"
|
||||
0
|
||||
[1]
|
||||
|
||||
$ cat out_bar | grep -ce "${O_CPPFLAGS}"
|
||||
0
|
||||
[1]
|
||||
|
||||
use_standard_c_and_cxx_flags = true but dune < 2.8
|
||||
================================================
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 2.7)
|
||||
> (use_standard_c_and_cxx_flags true)
|
||||
> EOF
|
||||
|
||||
$ dune rules
|
||||
File "dune-project", line 2, characters 0-35:
|
||||
2 | (use_standard_c_and_cxx_flags true)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Error: 'use_standard_c_and_cxx_flags' is only available since version 2.8 of
|
||||
the dune language. Please update your dune-project file to have (lang dune
|
||||
2.8).
|
||||
[1]
|
||||
|
||||
6
unikernel/duniverse/dune_/test/blackbox-tests/test-cases/foreign-stubs/c-flags.t/vendor/dune
vendored
Normal file
6
unikernel/duniverse/dune_/test/blackbox-tests/test-cases/foreign-stubs/c-flags.t/vendor/dune
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
(library
|
||||
(name testv)
|
||||
(foreign_stubs
|
||||
(language c)
|
||||
(names barv)
|
||||
(flags)))
|
||||
|
|
@ -0,0 +1 @@
|
|||
(lang dune 1.0)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
(library
|
||||
(name q)
|
||||
(c_names q_stub))
|
||||
|
|
@ -0,0 +1 @@
|
|||
#define ANSWER 42
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
external q : unit -> int = "ocaml_question"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
val q : unit -> int
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#include "q.h"
|
||||
#include <caml/mlvalues.h>
|
||||
#include <caml/memory.h>
|
||||
|
||||
CAMLprim value ocaml_question (value unit)
|
||||
{
|
||||
CAMLparam1 (unit);
|
||||
CAMLreturn (Val_int(ANSWER));
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
(executable
|
||||
(name run)
|
||||
(libraries q))
|
||||
|
|
@ -0,0 +1 @@
|
|||
print_int (Q.q ());;
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
Test that an OCaml executables with C stubs works.
|
||||
|
||||
$ dune exec ./qnativerun/run.exe
|
||||
42
|
||||
# $ dune exec ./qbyterun/run.bc
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <caml/misc.h>
|
||||
#include <caml/mlvalues.h>
|
||||
|
||||
// strdup is not part of the C standard library but is part of POSIX.
|
||||
// By default GCC and Clang both use the GNU variant of the C standard,
|
||||
// so we are using strdup here to ensure users have access to it by default.
|
||||
// If -std=c++11 is used instead of -std=gnu++11 this would fail to compile
|
||||
// on non-POSIX platforms such as Cygwin.
|
||||
extern "C" CAMLprim value cpp11(value _unit) {
|
||||
std::cout << strdup("Hi from C++11") << std::endl;
|
||||
return Val_unit;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
external cpp11 : unit -> unit = "cpp11"
|
||||
|
||||
let () = cpp11 ()
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
-std=c++11 is given on OCaml 5.0
|
||||
================================
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 3.14)
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> ;; will fail if :standard doesn't have -std=c++11 on OCaml >= 5.0
|
||||
> (executable
|
||||
> (name cpp11)
|
||||
> (foreign_stubs
|
||||
> (language cxx)
|
||||
> (names cpp11)
|
||||
> (flags -std=c++98 :standard)))
|
||||
> EOF
|
||||
|
||||
$ dune exec ./cpp11.exe
|
||||
Hi from C++11
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include "foo.cxx"
|
||||
|
||||
void foo () {
|
||||
int n = cppfoo();
|
||||
printf("n = %d\n", n);
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
Foo.foo ()
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
int cppfoo()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
external foo : unit -> unit = "foo"
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name foo)
|
||||
> (cxx_names foo)
|
||||
> (c_names bar)
|
||||
> (modules foo))
|
||||
>
|
||||
> (executable
|
||||
> (name bar)
|
||||
> (libraries foo)
|
||||
> (modules bar))
|
||||
>
|
||||
> (alias
|
||||
> (name default)
|
||||
> (action (run ./bar.exe)))
|
||||
> EOF
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 1.8)
|
||||
> EOF
|
||||
|
||||
* .cxx extension is allowed
|
||||
$ dune build
|
||||
n = 42
|
||||
|
||||
$ echo "(lang dune 1.11)" > dune-project
|
||||
|
||||
* Compilation succeeds when unused baz.cpp and baz.cxx exist
|
||||
|
||||
$ cat >baz.cpp <<EOF
|
||||
> #include <stdio.h>
|
||||
> extern "C" void foo () {
|
||||
> printf("m = %d\n", 42);
|
||||
> }
|
||||
> EOF
|
||||
|
||||
$ cat >baz.cxx <<EOF
|
||||
> #include <stdio.h>
|
||||
> extern "C" void foo () {
|
||||
> printf("k = %d\n", 42);
|
||||
> }
|
||||
> EOF
|
||||
|
||||
$ dune clean
|
||||
$ dune build
|
||||
n = 42
|
||||
|
||||
* Compilation fails when baz.cpp and baz.cxx conflict
|
||||
* Note that this behaviour differs from earlier Dune version
|
||||
that simply pick one of the sources and compile it to baz.o
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name foo)
|
||||
> (cxx_names baz)
|
||||
> (modules foo))
|
||||
> (executable
|
||||
> (name bar)
|
||||
> (libraries foo)
|
||||
> (modules bar))
|
||||
> (alias
|
||||
> (name default)
|
||||
> (action (run ./bar.exe)))
|
||||
> EOF
|
||||
|
||||
$ dune clean
|
||||
$ dune build
|
||||
File "dune", line 3, characters 11-14:
|
||||
3 | (cxx_names baz)
|
||||
^^^
|
||||
Error: Multiple sources map to the same object name "baz":
|
||||
- baz.cpp
|
||||
- baz.cxx
|
||||
This is not allowed; please rename them or remove "baz" from object names.
|
||||
Hint: You can also avoid the name clash by placing the objects into different
|
||||
foreign archives and building them in different directories. Foreign archives
|
||||
can be defined using the (foreign_library ...) stanza.
|
||||
[1]
|
||||
|
||||
* Compilation succeeds when using :standard in pre-2.0 Dune language.
|
||||
This works because the translation layer from pre-2.0 to 2.0 replaces
|
||||
:standard with the empty set.
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name foo)
|
||||
> (cxx_names :standard foo)
|
||||
> (c_names bar)
|
||||
> (modules foo))
|
||||
> (executable
|
||||
> (name bar)
|
||||
> (libraries foo)
|
||||
> (modules bar))
|
||||
> (alias
|
||||
> (name default)
|
||||
> (action (run ./bar.exe)))
|
||||
> EOF
|
||||
|
||||
$ dune clean
|
||||
$ dune build
|
||||
n = 42
|
||||
|
||||
* Compilation fails when using :standard in Dune 2.0
|
||||
|
||||
$ echo "(lang dune 2.0)" > dune-project
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name foo)
|
||||
> (foreign_stubs (language cxx) (names :standard foo))
|
||||
> (foreign_stubs (language c) (names bar))
|
||||
> (modules foo))
|
||||
> (executable
|
||||
> (name bar)
|
||||
> (libraries foo)
|
||||
> (modules bar))
|
||||
> (rule
|
||||
> (alias default)
|
||||
> (action (run ./bar.exe)))
|
||||
> EOF
|
||||
|
||||
$ dune clean
|
||||
$ dune build
|
||||
File "dune", line 3, characters 0-52:
|
||||
3 | (foreign_stubs (language cxx) (names :standard foo))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Error: Multiple sources map to the same object name "baz":
|
||||
- baz.cpp
|
||||
- baz.cxx
|
||||
This is not allowed; please rename them or remove "baz" from object names.
|
||||
Hint: You can also avoid the name clash by placing the objects into different
|
||||
foreign archives and building them in different directories. Foreign archives
|
||||
can be defined using the (foreign_library ...) stanza.
|
||||
[1]
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#include <caml/mlvalues.h>
|
||||
#include <caml/io.h>
|
||||
#include <iostream>
|
||||
|
||||
extern "C" value baz(value unit) { return Val_int(2046); }
|
||||
|
||||
extern "C" void hello_world_baz ();
|
||||
|
||||
void hello_world_baz ()
|
||||
{
|
||||
std::cout << "Hello World Baz!\n";
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#include <caml/mlvalues.h>
|
||||
#include <iostream>
|
||||
|
||||
extern "C" value bazexe(value unit) { return Val_int(4096); }
|
||||
|
||||
extern "C" void hello_world_bazexe ();
|
||||
|
||||
void hello_world_bazexe ()
|
||||
{
|
||||
std::cout << "Hello World Bazexe!";
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
(library
|
||||
(name quad)
|
||||
(modules quad)
|
||||
(foreign_stubs (language cxx) (names baz)))
|
||||
|
||||
(executable
|
||||
(name main)
|
||||
(libraries quad)
|
||||
(foreign_stubs (language cxx) (names bazexe))
|
||||
(modules main))
|
||||
|
||||
(env
|
||||
(_
|
||||
(ocamlopt_flags
|
||||
:standard
|
||||
(:include extra_flags.sexp))))
|
||||
|
||||
(rule
|
||||
(enabled_if
|
||||
(or
|
||||
(<> %{system} macosx)
|
||||
(<> %{architecture} arm64)))
|
||||
(action
|
||||
(write-file extra_flags.sexp "()")))
|
||||
|
||||
; with XCode 15+, the linker complains about duplicate -lc++ libraries
|
||||
(rule
|
||||
(enabled_if
|
||||
(and
|
||||
(= %{system} macosx)
|
||||
(= %{architecture} arm64)))
|
||||
(action
|
||||
(write-file extra_flags.sexp "(-ccopt -Wl,-no_warn_duplicate_libraries)")))
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
external bazexe : unit -> int = "bazexe"
|
||||
external hello_world_bazexe : unit -> unit = "hello_world_bazexe"
|
||||
|
||||
let () = Quad.hello (); hello_world_bazexe ()
|
||||
|
||||
|
||||
let () = Printf.printf "%d\n%d\n"
|
||||
(Quad.quad ())
|
||||
(bazexe ())
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
external baz : unit -> int = "baz"
|
||||
|
||||
external hello_world_baz : unit -> unit = "hello_world_baz"
|
||||
|
||||
let quad x = baz x
|
||||
let hello () = hello_world_baz ()
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
Default: use_standard_c_and_cxx_flags = false
|
||||
=============================================
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 2.8)
|
||||
> EOF
|
||||
|
||||
> The flags that Dune should use for compilation
|
||||
$ GCC_CF="-x c++"
|
||||
$ Clang_CF="-x c++"
|
||||
$ Msvc_CF="/TP"
|
||||
|
||||
> And linking
|
||||
$ GCC_LF_OPT=" -ldopt -lstdc++ -ldopt -shared-libgcc"
|
||||
$ Clang_LF_OPT=" -ldopt -lc++"
|
||||
$ Msvc_LF_OPT=""
|
||||
$ GCC_LF_LIB=" -cclib -lstdc++ -cclib -shared-libgcc"
|
||||
$ Clang_LF_LIB=" -cclib -lc++"
|
||||
$ Msvc_LF_LIB=""
|
||||
|
||||
> Check that compiler detection is done
|
||||
$ dune build .dune/cc_vendor/cc_vendor
|
||||
|
||||
$ cat _build/default/.dune/cc_vendor/cc_vendor |
|
||||
> grep -ce "clang\|gcc\|msvc"
|
||||
1
|
||||
|
||||
> No specific flags added for compilation...
|
||||
$ dune rules baz.o | tr -s '\n' ' ' |
|
||||
> grep -ce "$GCC_CF\|$Clang_CF|$Msvc_CF"
|
||||
0
|
||||
[1]
|
||||
|
||||
$ dune rules bazexe.o | tr -s '\n' ' ' |
|
||||
> grep -ce "$GCC_CF\|$Clang_CF\|$Msvc_CF"
|
||||
0
|
||||
[1]
|
||||
|
||||
> ...nor linking
|
||||
$ dune rules libquad_stubs.a | tr -s '\n' ' ' |
|
||||
> grep -ce "quad_stubs baz.o)"
|
||||
1
|
||||
|
||||
$ dune rules main.exe | tr -s '\n' ' ' |
|
||||
> grep -ce "Main.cmx)"
|
||||
1
|
||||
|
||||
With use_standard_c_and_cxx_flags = false
|
||||
=========================================
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 2.8)
|
||||
> (use_standard_c_and_cxx_flags false)
|
||||
> EOF
|
||||
|
||||
> No specific flags added for compilation...
|
||||
$ dune rules baz.o | tr -s '\n' ' ' |
|
||||
> grep -ce "$GCC_CF\|$Clang_CF|$Msvc_CF"
|
||||
0
|
||||
[1]
|
||||
|
||||
$ dune rules bazexe.o | tr -s '\n' ' ' |
|
||||
> grep -ce "$GCC_CF\|$Clang_CF\|$Msvc_CF"
|
||||
0
|
||||
[1]
|
||||
|
||||
> ...nor linking
|
||||
$ dune rules libquad_stubs.a | tr -s '\n' ' ' |
|
||||
> grep -ce "quad_stubs baz.o)"
|
||||
1
|
||||
|
||||
$ dune rules main.exe | tr -s '\n' ' ' |
|
||||
> grep -ce "Main.cmx)"
|
||||
1
|
||||
|
||||
With use_standard_c_and_cxx_flags = true
|
||||
========================================
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 2.8)
|
||||
> (use_standard_c_and_cxx_flags true)
|
||||
> EOF
|
||||
|
||||
> Check that compiler detection is done
|
||||
$ dune build .dune/cc_vendor/cc_vendor
|
||||
|
||||
$ cat _build/default/.dune/cc_vendor/cc_vendor |
|
||||
> grep -ce "clang\|gcc\|msvc"
|
||||
1
|
||||
|
||||
> Specific flags added for compilation...
|
||||
$ dune rules baz.o | tr -s '\n' ' ' |
|
||||
> grep -ce "$GCC_CF\|$Clang_CF\|$Msvc_CF"
|
||||
1
|
||||
|
||||
$ dune rules bazexe.o | tr -s '\n' ' ' |
|
||||
> grep -ce "$GCC_CF\|$Clang_CF\|$Msvc_CF"
|
||||
1
|
||||
|
||||
> ..and link
|
||||
$ dune rules libquad_stubs.a | tr -s '\n' ' ' |
|
||||
> grep -ce "quad_stubs baz.o$GCC_LF_OPT)\|quad_stubs baz.o$Clang_LF_OPT)\|quad_stubs baz.o$Msvc_LF_OPT)"
|
||||
1
|
||||
|
||||
$ dune rules main.exe | tr -s '\n' ' ' |
|
||||
> grep -ce "Main.cmx$GCC_LF_LIB)\|Main.cmx$Clang_LF_LIB)\|Main.cmx$Msvc_LF_LIB)"
|
||||
1
|
||||
|
||||
$ dune clean
|
||||
|
||||
$ dune exec ./main.exe
|
||||
2046
|
||||
4096
|
||||
Hello World Baz!
|
||||
Hello World Bazexe!
|
||||
|
||||
$ [ -f _build/default/.dune/cc_vendor/cc_vendor ]
|
||||
|
||||
(this also works with sandbox=symlink, #6415)
|
||||
|
||||
$ dune exec --sandbox symlink ./main.exe
|
||||
2046
|
||||
4096
|
||||
Hello World Baz!
|
||||
Hello World Bazexe!
|
||||
|
||||
cc_vendor is not computed if not required
|
||||
=====================================
|
||||
$ dune clean
|
||||
|
||||
$ dune exec ./sub/main_no_stubs.exe
|
||||
OK
|
||||
|
||||
$ [ -f _build/default/.dune/cc_vendor/cc_vendor ]
|
||||
[1]
|
||||
|
||||
|
||||
one can extend link flags in env
|
||||
================================
|
||||
|
||||
$ OTHER=" --other-flag --yet-some-other-flag)"
|
||||
|
||||
$ dune rules sub/main.exe --profile some-profile | tr -s '\n' ' ' |
|
||||
> grep -ce "Main.cmx$GCC_LF_LIB$OTHER\|Main.cmx$Clang_LF_LIB$OTHER\|Main.cmx$Msvc_LF_LIB$OTHER"
|
||||
1
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#include <caml/mlvalues.h>
|
||||
#include <iostream>
|
||||
|
||||
extern "C" value bazexe(value unit) { return Val_int(4096); }
|
||||
|
||||
extern "C" void hello_world_bazexe ();
|
||||
|
||||
void hello_world_bazexe ()
|
||||
{
|
||||
std::cout << "Hello World Bazexe!";
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
(executable
|
||||
(name main)
|
||||
(link_flags (:standard --yet-some-other-flag \ --remove-this-one-later))
|
||||
(foreign_stubs (language cxx) (names bazexe))
|
||||
(modules main))
|
||||
|
||||
(executable
|
||||
(name main_no_stubs)
|
||||
(modules main_no_stubs))
|
||||
|
||||
(env (some-profile (link_flags (:standard --other-flag --remove-this-one-later))))
|
||||
|
|
@ -0,0 +1 @@
|
|||
(lang dune 3.0)
|
||||
|
|
@ -0,0 +1 @@
|
|||
let () = print_endline "OK"
|
||||
|
|
@ -0,0 +1 @@
|
|||
let () = print_endline "OK"
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
We demonstrate a strange property of the foreign stubs.
|
||||
|
||||
Although we introduce a dependency on all header files found in all source
|
||||
directories, we do not add include directories, so they aren't accessible.
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 3.8)
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (include_subdirs unqualified)
|
||||
> (executable
|
||||
> (name foo)
|
||||
> (foreign_stubs
|
||||
> (language c)
|
||||
> (names bar)))
|
||||
> EOF
|
||||
|
||||
$ touch foo.ml
|
||||
$ cat >bar.c <<EOF
|
||||
> void foo { }
|
||||
> EOF
|
||||
|
||||
$ mkdir subdir
|
||||
$ cat >subdir/dune <<EOF
|
||||
> (rule (with-stdout-to foo.h (system "exit 1")))
|
||||
> EOF
|
||||
|
||||
$ dune build foo.exe
|
||||
File "subdir/dune", line 1, characters 0-47:
|
||||
1 | (rule (with-stdout-to foo.h (system "exit 1")))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Command exited with code 1.
|
||||
[1]
|
||||
|
||||
The rules include the dependency on foo.h, but the include directory has to be
|
||||
added manually.
|
||||
|
||||
$ dune rules _build/default/bar.o | grep subdir
|
||||
(File (In_build_dir _build/default/subdir/foo.h))))
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
(cram
|
||||
(applies_to github3766)
|
||||
(enabled_if
|
||||
(>= %{ocaml_version} 4.12.0))
|
||||
(deps ./github3766.t/test.exe))
|
||||
|
||||
(subdir
|
||||
github3766.t
|
||||
(executable
|
||||
(libraries stdune spawn unix)
|
||||
(name test)))
|
||||
|
||||
(cram
|
||||
(deps sandboxed.sh))
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
(library
|
||||
(name foo)
|
||||
(modules ())
|
||||
(c_names foo))
|
||||
|
||||
(library
|
||||
(name bar)
|
||||
(modules ())
|
||||
(cxx_names foo))
|
||||
|
|
@ -0,0 +1 @@
|
|||
(lang dune 1.7)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
This test showcases that although libraries can technically have non overlapping
|
||||
stubs names, things are still broken if their .o files overlap:
|
||||
|
||||
$ dune build @all 2>&1 | dune_cmd sanitize
|
||||
File "dune", line 4, characters 10-13:
|
||||
4 | (c_names foo))
|
||||
^^^
|
||||
Error: Multiple definitions for the same object file "foo". See another
|
||||
definition at dune:9.
|
||||
Hint: You can avoid the name clash by renaming one of the objects, or by
|
||||
placing it into a different directory.
|
||||
|
|
@ -0,0 +1 @@
|
|||
(lang dune 1.7)
|
||||
|
|
@ -0,0 +1 @@
|
|||
int foo () { return 1; }
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
This test showcases that although libraries can technically have non overlapping
|
||||
stubs names, things are still broken if their .o files overlap:
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name foo)
|
||||
> (c_names foo sub/foo))
|
||||
> EOF
|
||||
|
||||
Another form of this bug is if the same source is present in different
|
||||
directories. In this case, the rules are fine, but this is probably not what the
|
||||
user intended.
|
||||
|
||||
$ dune build @all
|
||||
File "dune", line 3, characters 14-21:
|
||||
3 | (c_names foo sub/foo))
|
||||
^^^^^^^
|
||||
Error: Relative part of stub is not necessary and should be removed. To
|
||||
include sources in subdirectories, use the (include_subdirs ...) stanza.
|
||||
[1]
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (include_subdirs unqualified)
|
||||
> (library
|
||||
> (name foo)
|
||||
> (c_names foo))
|
||||
> EOF
|
||||
|
||||
$ dune build @all
|
||||
File "dune", line 4, characters 10-13:
|
||||
4 | (c_names foo))
|
||||
^^^
|
||||
Error: Multiple sources map to the same object name "foo":
|
||||
- foo.c
|
||||
- sub/foo.c
|
||||
This is not allowed; please rename them or remove "foo" from object names.
|
||||
Hint: You can also avoid the name clash by placing the objects into different
|
||||
foreign archives and building them in different directories. Foreign archives
|
||||
can be defined using the (foreign_library ...) stanza.
|
||||
[1]
|
||||
|
|
@ -0,0 +1 @@
|
|||
int bar () { return 0; }
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
(library
|
||||
(name foo)
|
||||
(modules ())
|
||||
(c_names foo))
|
||||
|
||||
(library
|
||||
(name bar)
|
||||
(modules ())
|
||||
(c_names foo))
|
||||
|
|
@ -0,0 +1 @@
|
|||
(lang dune 1.7)
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
c_names with overlapping names in different stanzas
|
||||
|
||||
$ dune build @all 2>&1 | dune_cmd sanitize
|
||||
File "dune", line 4, characters 10-13:
|
||||
4 | (c_names foo))
|
||||
^^^
|
||||
Error: Multiple definitions for the same object file "foo". See another
|
||||
definition at dune:9.
|
||||
Hint: You can avoid the name clash by renaming one of the objects, or by
|
||||
placing it into a different directory.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
(library
|
||||
(name foo)
|
||||
(c_names foo)
|
||||
(cxx_names foo))
|
||||
|
|
@ -0,0 +1 @@
|
|||
(lang dune 1.7)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
c_names and cxx_names with overlapping names in the same stanza
|
||||
|
||||
$ dune build @all
|
||||
File "dune", line 4, characters 12-15:
|
||||
4 | (cxx_names foo))
|
||||
^^^
|
||||
Error: Multiple sources map to the same object name "foo":
|
||||
- foo.c
|
||||
- foo.cpp
|
||||
This is not allowed; please rename them or remove "foo" from object names.
|
||||
Hint: You can also avoid the name clash by placing the objects into different
|
||||
foreign archives and building them in different directories. Foreign archives
|
||||
can be defined using the (foreign_library ...) stanza.
|
||||
[1]
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
external foo : string -> unit = "foo"
|
||||
|
||||
let () =
|
||||
foo "A"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
external foo : string -> unit = "foo"
|
||||
|
||||
let () =
|
||||
foo "B"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
(executables
|
||||
(names aa bb)
|
||||
(foreign_stubs (language c) (names foo))
|
||||
(modes exe))
|
||||
|
|
@ -0,0 +1 @@
|
|||
(lang dune 2.0)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include <caml/mlvalues.h>
|
||||
|
||||
void foo(value s)
|
||||
{
|
||||
puts(String_val(s));
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
$ dune exec ./aa.exe
|
||||
A
|
||||
$ dune exec ./bb.exe
|
||||
B
|
||||
|
||||
$ mkdir err
|
||||
$ echo "(lang dune 2.1)" > err/dune-project
|
||||
$ touch err/foo.ml err/stubs.c
|
||||
$ cat > err/dune << EOF
|
||||
> (executable
|
||||
> (name foo)
|
||||
> (modes exe byte)
|
||||
> (foreign_stubs (language c) (names stubs)))
|
||||
> EOF
|
||||
$ dune build --root err @all
|
||||
Entering directory 'err'
|
||||
File "dune", lines 1-4, characters 0-86:
|
||||
1 | (executable
|
||||
2 | (name foo)
|
||||
3 | (modes exe byte)
|
||||
4 | (foreign_stubs (language c) (names stubs)))
|
||||
Error: Pure bytecode executables cannot contain foreign stubs.
|
||||
Hint: If you only need to build a native executable use "(modes exe)".
|
||||
Leaving directory 'err'
|
||||
[1]
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
----------------------------------------------------------------------------------
|
||||
Build an executable which depends on foreign object files compiled with a rule.
|
||||
|
||||
$ echo "(lang dune 3.5)" > dune-project
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (executable
|
||||
> (name calc)
|
||||
> (extra_objects add mul))
|
||||
> (rule
|
||||
> (targets add.o mul.o)
|
||||
> (deps add.c mul.c)
|
||||
> (action (run %{cc} -c -I %{ocaml_where} %{deps})))
|
||||
> EOF
|
||||
|
||||
$ cat >calc.ml <<EOF
|
||||
> external add : int -> int -> int = "add"
|
||||
> external mul : int -> int -> int = "mul"
|
||||
> let calc x y z = mul (add x y) z
|
||||
> let () = print_int (calc 3 4 6)
|
||||
> let () = print_string "\n"
|
||||
> EOF
|
||||
|
||||
$ cat >add.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value add(value x, value y) { return Val_int(Int_val(x) + Int_val(y)); }
|
||||
> EOF
|
||||
|
||||
$ cat >mul.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value mul(value x, value y) { return Val_int(Int_val(x) * Int_val(y)); }
|
||||
> EOF
|
||||
|
||||
$ dune exec ./calc.exe
|
||||
42
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
----------------------------------------------------------------------------------
|
||||
Test that duplicate foreign objects results in an error
|
||||
|
||||
$ echo "(lang dune 3.5)" > dune-project
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (executable
|
||||
> (name foo)
|
||||
> (extra_objects foo foo))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "dune", line 3, characters 16-19:
|
||||
3 | (extra_objects foo foo))
|
||||
^^^
|
||||
Error: Duplicate object name: foo. Already appears at:
|
||||
- dune:3
|
||||
[1]
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
----------------------------------------------------------------------------------
|
||||
Build an executable which depends on foreign object files.
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* (extra_objects ...) is unavailable before Dune 3.5.
|
||||
|
||||
$ echo "(lang dune 3.4)" > dune-project
|
||||
$ mkdir -p bin
|
||||
|
||||
$ cat >bin/dune <<EOF
|
||||
> (executable
|
||||
> (name calc)
|
||||
> (extra_objects add mul))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "bin/dune", line 3, characters 1-24:
|
||||
3 | (extra_objects add mul))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Error: 'extra_objects' is only available since version 3.5 of the dune
|
||||
language. Please update your dune-project file to have (lang dune 3.5).
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error for missing object file
|
||||
|
||||
$ echo "(lang dune 3.5)" > dune-project
|
||||
|
||||
$ cat >bin/calc.ml <<EOF
|
||||
> external add : int -> int -> int = "add"
|
||||
> external mul : int -> int -> int = "mul"
|
||||
> let calc x y z = mul (add x y) z
|
||||
> let () = print_int (calc 3 4 6)
|
||||
> let () = print_string "\n"
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "bin/dune", line 2, characters 7-11:
|
||||
2 | (name calc)
|
||||
^^^^
|
||||
Error: No rule found for bin/add.o
|
||||
File "bin/dune", line 2, characters 7-11:
|
||||
2 | (name calc)
|
||||
^^^^
|
||||
Error: No rule found for bin/mul.o
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Successful build when all object files are available
|
||||
|
||||
$ cat >bin/add.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value add(value x, value y) { return Val_int(Int_val(x) + Int_val(y)); }
|
||||
> EOF
|
||||
|
||||
$ cat >bin/mul.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value mul(value x, value y) { return Val_int(Int_val(x) * Int_val(y)); }
|
||||
> EOF
|
||||
|
||||
$ cat >>bin/dune <<EOF
|
||||
> (rule
|
||||
> (target mul.o)
|
||||
> (deps mul.c)
|
||||
> (action (run %{bin:ocamlc} mul.c)))
|
||||
> (rule
|
||||
> (target add.o)
|
||||
> (deps add.c)
|
||||
> (action (run %{bin:ocamlc} add.c)))
|
||||
> EOF
|
||||
|
||||
$ dune exec ./bin/calc.exe
|
||||
42
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
----------------------------------------------------------------------------------
|
||||
Build an library which indirectly depends on foreign object files.
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Building library with indirect dependency on object file
|
||||
|
||||
$ echo "(lang dune 3.5)" > dune-project
|
||||
|
||||
$ mkdir -p lib
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (library
|
||||
> (name calc)
|
||||
> (extra_objects add)
|
||||
> (foreign_stubs (language c) (names dep)))
|
||||
> EOF
|
||||
|
||||
$ cat >lib/calc.ml <<EOF
|
||||
> external add : int -> int -> int = "add"
|
||||
> EOF
|
||||
|
||||
$ cat >lib/dep.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> extern value add(value x, value y);
|
||||
> value dummy() { return add(Val_int(1), Val_int(2)); }
|
||||
> EOF
|
||||
|
||||
$ cat >lib/add.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value add(value x, value y) { return Val_int(Int_val(x) + Int_val(y)); }
|
||||
> EOF
|
||||
|
||||
$ cat >>lib/dune <<EOF
|
||||
> (rule
|
||||
> (target add.o)
|
||||
> (deps add.c)
|
||||
> (action (run %{bin:ocamlc} add.c)))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
----------------------------------------------------------------------------------
|
||||
Build a library which depends on foreign object files.
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* (extra_objects ...) is unavailable before Dune 3.5.
|
||||
|
||||
$ echo "(lang dune 3.4)" > dune-project
|
||||
$ mkdir -p lib
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (library
|
||||
> (name calc)
|
||||
> (extra_objects add mul))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "lib/dune", line 3, characters 1-24:
|
||||
3 | (extra_objects add mul))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Error: 'extra_objects' is only available since version 3.5 of the dune
|
||||
language. Please update your dune-project file to have (lang dune 3.5).
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error for missing object file
|
||||
|
||||
$ echo "(lang dune 3.5)" > dune-project
|
||||
|
||||
$ cat >lib/calc.ml <<EOF
|
||||
> external add : int -> int -> int = "add"
|
||||
> external mul : int -> int -> int = "mul"
|
||||
> let calc x y z = mul (add x y) z
|
||||
> EOF
|
||||
|
||||
$ cat >lib/calc.mli <<EOF
|
||||
> val calc : int -> int -> int -> int
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "lib/dune", lines 1-3, characters 0-47:
|
||||
1 | (library
|
||||
2 | (name calc)
|
||||
3 | (extra_objects add mul))
|
||||
Error: No rule found for lib/add.o
|
||||
File "lib/dune", lines 1-3, characters 0-47:
|
||||
1 | (library
|
||||
2 | (name calc)
|
||||
3 | (extra_objects add mul))
|
||||
Error: No rule found for lib/mul.o
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Successful build when all object files are available
|
||||
|
||||
$ cat >lib/add.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value add(value x, value y) { return Val_int(Int_val(x) + Int_val(y)); }
|
||||
> EOF
|
||||
|
||||
$ cat >lib/mul.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value mul(value x, value y) { return Val_int(Int_val(x) * Int_val(y)); }
|
||||
> EOF
|
||||
|
||||
$ cat >>lib/dune <<EOF
|
||||
> (rule
|
||||
> (target mul.o)
|
||||
> (deps mul.c)
|
||||
> (action (run %{bin:ocamlc} mul.c)))
|
||||
> (rule
|
||||
> (target add.o)
|
||||
> (deps add.c)
|
||||
> (action (run %{bin:ocamlc} add.c)))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Add an executable to test that we can link against the foreign object files
|
||||
|
||||
$ mkdir -p bin
|
||||
|
||||
$ cat >bin/dune <<EOF
|
||||
> (executable
|
||||
> (name main)
|
||||
> (libraries calc))
|
||||
> EOF
|
||||
|
||||
$ cat >bin/main.ml <<EOF
|
||||
> let () = print_int (Calc.calc 3 4 6)
|
||||
> let () = print_string "\n"
|
||||
> EOF
|
||||
|
||||
$ dune exec ./bin/main.exe
|
||||
42
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
Interaction of the foreign_library stanza and the enabled_if field.
|
||||
|
||||
$ cat > dune-project <<EOF
|
||||
> (lang dune 3.18)
|
||||
> EOF
|
||||
|
||||
$ cat > a.c <<EOF
|
||||
> int foo() {
|
||||
> return 1;
|
||||
> }
|
||||
> EOF
|
||||
|
||||
We should allow multiple foreign libraries to define the same archive if only
|
||||
one of them is enabled:
|
||||
|
||||
$ cat > dune <<EOF
|
||||
> (foreign_library
|
||||
> (enabled_if true)
|
||||
> (language c)
|
||||
> (archive_name a)
|
||||
> (names a))
|
||||
>
|
||||
> (foreign_library
|
||||
> (enabled_if false)
|
||||
> (language c)
|
||||
> (archive_name a)
|
||||
> (names a))
|
||||
>
|
||||
> (foreign_library
|
||||
> (enabled_if false)
|
||||
> (language c)
|
||||
> (archive_name a)
|
||||
> (names a))
|
||||
> EOF
|
||||
$ dune build
|
||||
|
||||
|
||||
Repeat the test, but now two of the libraries are indeed enabled which is
|
||||
illegal:
|
||||
|
||||
$ cat > dune <<EOF
|
||||
> (foreign_library
|
||||
> (enabled_if true)
|
||||
> (language c)
|
||||
> (archive_name a)
|
||||
> (names a))
|
||||
>
|
||||
> (foreign_library
|
||||
> (enabled_if true)
|
||||
> (language c)
|
||||
> (archive_name a)
|
||||
> (names a))
|
||||
>
|
||||
> (foreign_library
|
||||
> (enabled_if false)
|
||||
> (language c)
|
||||
> (archive_name a)
|
||||
> (names a))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "dune", line 5, characters 8-9:
|
||||
5 | (names a))
|
||||
^
|
||||
Error: Multiple definitions for the same object file "a". See another
|
||||
definition at dune:11.
|
||||
Hint: You can avoid the name clash by renaming one of the objects, or by
|
||||
placing it into a different directory.
|
||||
[1]
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
Testing extra_objects in foreign libraries
|
||||
|
||||
$ cat > dune-project <<EOF
|
||||
> (lang dune 3.19)
|
||||
> EOF
|
||||
|
||||
First we create a foreign library that uses an extra object file containing our message.
|
||||
|
||||
$ cat > dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name foo)
|
||||
> (names foo)
|
||||
> (language c)
|
||||
> (extra_objects message))
|
||||
> EOF
|
||||
|
||||
$ cat > foo.c <<EOF
|
||||
> #include <stdio.h>
|
||||
> extern char *message;
|
||||
> int f() { printf("%s\n", message); return 0; }
|
||||
> EOF
|
||||
|
||||
Our message is compiled separately from the foreign library and the object file is
|
||||
included in the (extra_objects) field.
|
||||
$ cat > message.c <<EOF
|
||||
> char *message = "Hello from C!";
|
||||
> EOF
|
||||
$ ocamlopt -c message.c -o message.o
|
||||
|
||||
We create a test executable that links against the foreign library to check everything is
|
||||
working as intended.
|
||||
$ cat > test.c <<EOF
|
||||
> #include <stdio.h>
|
||||
> extern int f();
|
||||
> int main() { return f(); }
|
||||
> EOF
|
||||
|
||||
$ dune build _build/default/libfoo.a
|
||||
|
||||
$ ocamlopt test.c _build/default/libfoo.a -o test.exe
|
||||
$ chmod +x test.exe
|
||||
|
||||
Our test executable works as intended and prints the message from the object file.
|
||||
$ ./test.exe
|
||||
Hello from C!
|
||||
|
||||
$ rm test.exe
|
||||
$ rm test.o
|
||||
$ rm message.o
|
||||
|
||||
Testing that (:include) works
|
||||
|
||||
$ cat > dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name foo)
|
||||
> (names foo)
|
||||
> (language c)
|
||||
> (extra_objects
|
||||
> (:include message.in)))
|
||||
> EOF
|
||||
|
||||
$ cat > message.in <<EOF
|
||||
> message
|
||||
> EOF
|
||||
|
||||
$ cat > message.c <<EOF
|
||||
> char *message = "Hello from C with an (:include)!";
|
||||
> EOF
|
||||
$ ocamlopt -c message.c -o message.o
|
||||
|
||||
$ dune build _build/default/libfoo.a
|
||||
$ ocamlopt test.c _build/default/libfoo.a -o test.exe
|
||||
$ chmod +x test.exe
|
||||
$ ./test.exe
|
||||
Hello from C with an (:include)!
|
||||
|
||||
Testing how (:include) interacts with a non-existant file.
|
||||
$ rm message.in test.exe test.o
|
||||
|
||||
$ dune build _build/default/libfoo.a
|
||||
File "dune", lines 1-6, characters 0-105:
|
||||
1 | (foreign_library
|
||||
2 | (archive_name foo)
|
||||
3 | (names foo)
|
||||
4 | (language c)
|
||||
5 | (extra_objects
|
||||
6 | (:include message.in)))
|
||||
Error: No rule found for message.in
|
||||
[1]
|
||||
|
||||
Testing how (:include) interacts when returning a non-existent object file.
|
||||
|
||||
$ cat > message.in <<EOF
|
||||
> foobar
|
||||
> EOF
|
||||
|
||||
$ dune build _build/default/libfoo.a
|
||||
File "dune", lines 1-6, characters 0-105:
|
||||
1 | (foreign_library
|
||||
2 | (archive_name foo)
|
||||
3 | (names foo)
|
||||
4 | (language c)
|
||||
5 | (extra_objects
|
||||
6 | (:include message.in)))
|
||||
Error: No rule found for foobar.o
|
||||
[1]
|
||||
|
|
@ -0,0 +1,887 @@
|
|||
----------------------------------------------------------------------------------
|
||||
Testsuite for the (foreign_library ...) stanza.
|
||||
|
||||
$ export DUNE_SANDBOX=symlink
|
||||
$ echo "(lang dune 3.0)" > dune-project
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Multiple (foreign_library ...) declarations.
|
||||
* Mixing C and C++ foreign library archives.
|
||||
* Passing flags via (flags ...) field.
|
||||
* Interaction with (foreign_archives ...) stanza.
|
||||
|
||||
$ mkdir lib
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names add mul))
|
||||
> (library
|
||||
> (name calc)
|
||||
> (modules calc)
|
||||
> (foreign_archives addmul config))
|
||||
> (foreign_library
|
||||
> (archive_name config)
|
||||
> (language cxx)
|
||||
> (flags :standard -DCONFIG_VALUE=2000)
|
||||
> (names config))
|
||||
> EOF
|
||||
|
||||
$ cat >lib/add.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value add(value x, value y) { return Val_int(Int_val(x) + Int_val(y)); }
|
||||
> EOF
|
||||
|
||||
$ cat >lib/mul.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value mul(value x, value y) { return Val_int(Int_val(x) * Int_val(y)); }
|
||||
> EOF
|
||||
|
||||
$ cat >lib/config.cpp <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> extern "C" value config(value unit) { return Val_int(CONFIG_VALUE); }
|
||||
> EOF
|
||||
|
||||
$ cat >lib/calc.ml <<EOF
|
||||
> external add : int -> int -> int = "add"
|
||||
> external mul : int -> int -> int = "mul"
|
||||
> external config : unit -> int = "config"
|
||||
> let calc x y z = add (mul (add x y) z) (config ())
|
||||
> EOF
|
||||
|
||||
$ cat >lib/calc.mli <<EOF
|
||||
> val calc : int -> int -> int -> int
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (executable
|
||||
> (name main)
|
||||
> (modes exe byte)
|
||||
> (libraries calc)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ cat >main.ml <<EOF
|
||||
> let () = Printf.printf "%d" (Calc.calc 1 2 3)
|
||||
> EOF
|
||||
|
||||
$ rm -rf _build
|
||||
$ dune build
|
||||
|
||||
$ dune exec ./main.exe
|
||||
2009
|
||||
|
||||
$ (cd _build/default && ocamlrun -I lib main.bc)
|
||||
2009
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Include directories via the (include_dirs ...) field.
|
||||
* Extra dependencies via the (extra_deps ...) field.
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names add mul))
|
||||
> (library
|
||||
> (name calc)
|
||||
> (modules calc)
|
||||
> (foreign_archives addmul config))
|
||||
> (foreign_library
|
||||
> (archive_name config)
|
||||
> (language cxx)
|
||||
> (include_dirs headers)
|
||||
> (extra_deps eight.h)
|
||||
> (flags :standard -DCONFIG_VALUE=2000)
|
||||
> (names config))
|
||||
> EOF
|
||||
|
||||
$ cat >lib/config.cpp <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> #include "ten.h"
|
||||
> extern "C" value config(value unit) { return Val_int(CONFIG_VALUE + TEN); }
|
||||
> EOF
|
||||
|
||||
$ mkdir -p lib/headers
|
||||
$ cat >lib/headers/ten.h <<EOF
|
||||
> #include "../eight.h"
|
||||
> #include "some/deep/path/one.h"
|
||||
> #define TEN (1 + EIGHT + ONE)
|
||||
> EOF
|
||||
|
||||
$ mkdir -p lib/headers/some/deep/path
|
||||
$ cat >lib/headers/some/deep/path/one.h <<EOF
|
||||
> #define ONE 1
|
||||
> EOF
|
||||
|
||||
$ cat >lib/eight.h <<EOF
|
||||
> #define EIGHT 8
|
||||
> EOF
|
||||
|
||||
$ rm -rf _build
|
||||
$ dune build
|
||||
|
||||
$ dune exec ./main.exe
|
||||
2019
|
||||
|
||||
$ (cd _build/default && ocamlrun -I lib main.bc)
|
||||
2019
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error message when a given (include_dir ...) is not found.
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names add mul))
|
||||
> (library
|
||||
> (name calc)
|
||||
> (modules calc)
|
||||
> (foreign_archives addmul config))
|
||||
> (foreign_library
|
||||
> (archive_name config)
|
||||
> (language cxx)
|
||||
> (include_dirs headers another/dir)
|
||||
> (extra_deps eight.h)
|
||||
> (flags :standard -DCONFIG_VALUE=2000)
|
||||
> (names config))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "lib/dune", line 12, characters 23-34:
|
||||
12 | (include_dirs headers another/dir)
|
||||
^^^^^^^^^^^
|
||||
Error: Include directory "another/dir" does not exist.
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error when specifying a non-existing external directory in (include_dirs... )
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names add mul))
|
||||
> (library
|
||||
> (name calc)
|
||||
> (modules calc)
|
||||
> (foreign_archives addmul config))
|
||||
> (foreign_library
|
||||
> (archive_name config)
|
||||
> (language cxx)
|
||||
> (include_dirs headers /some/path)
|
||||
> (extra_deps eight.h)
|
||||
> (flags :standard -DCONFIG_VALUE=2000)
|
||||
> (names config))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "lib/dune", line 12, characters 23-33:
|
||||
12 | (include_dirs headers /some/path)
|
||||
^^^^^^^^^^
|
||||
Error: Unable to read the include directory.
|
||||
Reason: stat(/some/path): No such file or directory.
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error when specifying an external file in (include_dirs... )
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names add mul))
|
||||
> (library
|
||||
> (name calc)
|
||||
> (modules calc)
|
||||
> (foreign_archives addmul config))
|
||||
> (foreign_library
|
||||
> (archive_name config)
|
||||
> (language cxx)
|
||||
> (include_dirs headers /usr/bin/env)
|
||||
> (extra_deps eight.h)
|
||||
> (flags :standard -DCONFIG_VALUE=2000)
|
||||
> (names config))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "lib/dune", line 12, characters 23-35:
|
||||
12 | (include_dirs headers /usr/bin/env)
|
||||
^^^^^^^^^^^^
|
||||
Error: Unable to read the include directory.
|
||||
Reason: "/usr/bin/env" is not a directory.
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error message for multiple declarations with the same "archive_name".
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names add))
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names mul))
|
||||
> (library
|
||||
> (name calc)
|
||||
> (modules calc)
|
||||
> (foreign_archives addmul config))
|
||||
> (foreign_library
|
||||
> (archive_name config)
|
||||
> (language cxx)
|
||||
> (include_dirs headers)
|
||||
> (extra_deps eight.h)
|
||||
> (flags :standard -DCONFIG_VALUE=2000)
|
||||
> (names config))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "lib/dune", line 6, characters 1-22:
|
||||
6 | (archive_name addmul)
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
Error: Multiple foreign libraries with the same archive name "addmul"; the
|
||||
name has already been taken in lib/dune:2.
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Interaction of (foreign_stubs ...) and (foreign_archives ...).
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names add mul))
|
||||
> (library
|
||||
> (name calc)
|
||||
> (modules calc)
|
||||
> (foreign_stubs (language c) (names month))
|
||||
> (foreign_archives addmul config))
|
||||
> (foreign_library
|
||||
> (archive_name config)
|
||||
> (language cxx)
|
||||
> (include_dirs headers)
|
||||
> (extra_deps eight.h)
|
||||
> (flags :standard -DCONFIG_VALUE=2000)
|
||||
> (names config))
|
||||
> EOF
|
||||
|
||||
$ cat >lib/month.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> #include <caml/alloc.h>
|
||||
> value month(value unit) { return caml_copy_string("October"); }
|
||||
> EOF
|
||||
|
||||
$ cat >lib/calc.ml <<EOF
|
||||
> external add : int -> int -> int = "add"
|
||||
> external mul : int -> int -> int = "mul"
|
||||
> external config : unit -> int = "config"
|
||||
> external month : unit -> string = "month"
|
||||
> let calc x y z = add (mul (add x y) z) (config ())
|
||||
> EOF
|
||||
|
||||
$ cat >lib/calc.mli <<EOF
|
||||
> val calc : int -> int -> int -> int
|
||||
> val month : unit -> string
|
||||
> EOF
|
||||
|
||||
$ cat >main.ml <<EOF
|
||||
> let () = Printf.printf "%s %d" (Calc.month ()) (Calc.calc 1 2 3)
|
||||
> EOF
|
||||
|
||||
$ rm -rf _build
|
||||
$ dune build
|
||||
|
||||
$ dune exec ./main.exe
|
||||
October 2019
|
||||
|
||||
$ (cd _build/default && ocamlrun -I lib main.bc)
|
||||
October 2019
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error when using (foreign_archives ...) and a pure bytecode (executable ...).
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names add mul))
|
||||
> (library
|
||||
> (name calc)
|
||||
> (modules calc)
|
||||
> (foreign_stubs (language c) (names month))
|
||||
> (foreign_archives addmul config))
|
||||
> (foreign_library
|
||||
> (archive_name day)
|
||||
> (language c)
|
||||
> (names day))
|
||||
> (foreign_library
|
||||
> (archive_name config)
|
||||
> (language cxx)
|
||||
> (include_dirs headers)
|
||||
> (extra_deps eight.h)
|
||||
> (flags :standard -DCONFIG_VALUE=2000)
|
||||
> (names config))
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (executable
|
||||
> (name main)
|
||||
> (modes exe byte)
|
||||
> (libraries calc)
|
||||
> (foreign_archives lib/day)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ cat >lib/day.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value day(value unit) { return Val_int(8); }
|
||||
> EOF
|
||||
|
||||
$ cat >main.ml <<EOF
|
||||
> external day : unit -> int = "day"
|
||||
> let () = Printf.printf "%d %s %d" (day ()) (Calc.month ()) (Calc.calc 1 2 3)
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "dune", lines 1-6, characters 0-105:
|
||||
1 | (executable
|
||||
2 | (name main)
|
||||
3 | (modes exe byte)
|
||||
4 | (libraries calc)
|
||||
5 | (foreign_archives lib/day)
|
||||
6 | (modules main))
|
||||
Error: Pure bytecode executables cannot contain foreign archives.
|
||||
Hint: If you only need to build a native executable use "(modes exe)".
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Interaction of (foreign_archives ...) and (executables ...).
|
||||
* Foreign archives in subdirectories.
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names add mul))
|
||||
> (library
|
||||
> (name calc)
|
||||
> (modules calc)
|
||||
> (foreign_stubs (language c) (names month))
|
||||
> (foreign_archives addmul config))
|
||||
> (foreign_library
|
||||
> (archive_name day)
|
||||
> (language c)
|
||||
> (names day))
|
||||
> (foreign_library
|
||||
> (archive_name config)
|
||||
> (language cxx)
|
||||
> (include_dirs headers)
|
||||
> (extra_deps eight.h)
|
||||
> (flags :standard -DCONFIG_VALUE=2000)
|
||||
> (names config))
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (executable
|
||||
> (modes exe)
|
||||
> (name main)
|
||||
> (libraries calc)
|
||||
> (foreign_archives lib/day)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ cat >lib/day.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value day(value unit) { return Val_int(8); }
|
||||
> EOF
|
||||
|
||||
$ cat >main.ml <<EOF
|
||||
> external day : unit -> int = "day"
|
||||
> let () = Printf.printf "%d %s %d" (day ()) (Calc.month ()) (Calc.calc 1 2 3)
|
||||
> EOF
|
||||
|
||||
$ rm -rf _build
|
||||
$ dune build
|
||||
|
||||
$ dune exec ./main.exe
|
||||
8 October 2019
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Use (env ...) to pass C++ flags.
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names add mul))
|
||||
> (library
|
||||
> (name calc)
|
||||
> (modules calc)
|
||||
> (foreign_stubs (language c) (names month))
|
||||
> (foreign_archives addmul config))
|
||||
> (foreign_library
|
||||
> (archive_name day)
|
||||
> (language c)
|
||||
> (names day))
|
||||
> (foreign_library
|
||||
> (archive_name config)
|
||||
> (language cxx)
|
||||
> (include_dirs headers)
|
||||
> (extra_deps eight.h)
|
||||
> (names config))
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (env (_ (cxx_flags :standard -DCONFIG_VALUE=2000)))
|
||||
> (executable
|
||||
> (modes exe)
|
||||
> (name main)
|
||||
> (libraries calc)
|
||||
> (foreign_archives lib/day)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ dune exec ./main.exe
|
||||
8 October 2019
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Generated header.
|
||||
|
||||
$ cat >lib/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name addmul)
|
||||
> (language c)
|
||||
> (names add mul))
|
||||
> (library
|
||||
> (name calc)
|
||||
> (modules calc)
|
||||
> (foreign_stubs (language c) (names month))
|
||||
> (foreign_archives addmul config))
|
||||
> (foreign_library
|
||||
> (archive_name day)
|
||||
> (language c)
|
||||
> (names day))
|
||||
> (foreign_library
|
||||
> (archive_name config)
|
||||
> (language cxx)
|
||||
> (include_dirs headers)
|
||||
> (flags :standard -DCONFIG_VALUE=2000)
|
||||
> (extra_deps eight.h)
|
||||
> (names config))
|
||||
> EOF
|
||||
|
||||
$ mkdir -p lib2/headers
|
||||
$ cat >lib2/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name today)
|
||||
> (language c)
|
||||
> (include_dirs headers)
|
||||
> (names today))
|
||||
> EOF
|
||||
|
||||
$ cat >lib2/headers/dune <<EOF
|
||||
> (rule
|
||||
> (action (write-file today.h "#define TODAY \"Today\"")))
|
||||
> EOF
|
||||
|
||||
$ cat >lib2/today.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> #include <caml/alloc.h>
|
||||
> #include "today.h"
|
||||
> value today(value unit) { return caml_copy_string(TODAY); }
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (executable
|
||||
> (name main)
|
||||
> (modes exe)
|
||||
> (libraries calc)
|
||||
> (foreign_archives lib/day lib2/today)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ cat >main.ml <<EOF
|
||||
> external day : unit -> int = "day"
|
||||
> external today : unit -> string = "today"
|
||||
> let () = Printf.printf "%s: %d %s %d" (today ()) (day ()) (Calc.month ()) (Calc.calc 1 2 3)
|
||||
> EOF
|
||||
|
||||
$ rm -rf _build
|
||||
$ dune exec ./main.exe
|
||||
Today: 8 October 2019
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Object files with the same name in different archives.
|
||||
* Generated C source file.
|
||||
|
||||
$ mkdir -p lib3
|
||||
$ cat >lib3/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name new_day)
|
||||
> (language c)
|
||||
> (names day))
|
||||
> (rule
|
||||
> (action (write-file day.c "#include <caml/mlvalues.h>\nvalue new_day(value unit) { return Val_int(14); }\n")))
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (executable
|
||||
> (name main)
|
||||
> (modes exe)
|
||||
> (libraries calc)
|
||||
> (foreign_archives lib/day lib2/today lib3/new_day)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ cat >main.ml <<EOF
|
||||
> external day : unit -> int = "day"
|
||||
> external today : unit -> string = "today"
|
||||
> external new_day : unit -> int = "new_day"
|
||||
> let () = Printf.printf "%s: %02d %s %d\n" (today ()) ( day ()) (Calc.month ()) (Calc.calc 1 2 3);
|
||||
> Printf.printf "%s: %02d %s %d\n" (today ()) (new_day ()) (Calc.month ()) (Calc.calc 1 2 3);
|
||||
> EOF
|
||||
|
||||
$ rm -rf _build
|
||||
$ dune exec ./main.exe
|
||||
Today: 08 October 2019
|
||||
Today: 14 October 2019
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Library directories in (include_dir ...)
|
||||
* Build fails due to the missing "header.h"
|
||||
|
||||
$ mkdir -p some/dir/answer
|
||||
$ cat >some/dir/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name clib)
|
||||
> (language c)
|
||||
> (names src))
|
||||
> (executable
|
||||
> (modes exe)
|
||||
> (name main)
|
||||
> (foreign_archives clib)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ cat >some/dir/answer/dune <<EOF
|
||||
> (library
|
||||
> (name answer))
|
||||
> EOF
|
||||
|
||||
$ cat >some/dir/answer/header.h <<EOF
|
||||
> #define ANSWER 42
|
||||
> EOF
|
||||
|
||||
$ cat >some/dir/src.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> #include "header.h"
|
||||
> value answer(value unit) { return Val_int(ANSWER); }
|
||||
> EOF
|
||||
|
||||
$ cat >some/dir/main.ml <<EOF
|
||||
> external answer : unit -> int = "answer"
|
||||
> let () = Printf.printf "Answer = %d\n" (answer ());
|
||||
> EOF
|
||||
|
||||
$ rm -rf _build
|
||||
$ dune exec some/dir/main.exe 2> /dev/null
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Library directories in (include_dir ...)
|
||||
* Build succeeds
|
||||
|
||||
$ cat >some/dir/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name clib)
|
||||
> (language c)
|
||||
> (include_dirs (lib answer))
|
||||
> (names src))
|
||||
> (executable
|
||||
> (modes exe)
|
||||
> (name main)
|
||||
> (foreign_archives clib)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ rm -rf _build
|
||||
$ dune exec some/dir/main.exe
|
||||
Answer = 42
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* External library directories in (include_dir ...)
|
||||
* Using an external directory in (include_dir ...)
|
||||
|
||||
$ mkdir -p external
|
||||
|
||||
$ cat >external/dune-project <<EOF
|
||||
> (lang dune 2.1)
|
||||
> (name external_library)
|
||||
> EOF
|
||||
|
||||
$ cat >external/dune <<EOF
|
||||
> (library
|
||||
> (name extlib)
|
||||
> (public_name external_library)
|
||||
> (install_c_headers correction))
|
||||
> EOF
|
||||
|
||||
$ cat >external/correction.h <<EOF
|
||||
> #define CORRECTION (-21)
|
||||
> EOF
|
||||
|
||||
$ rm -rf _build
|
||||
$ touch external/external_library.opam
|
||||
$ ( cd external && dune build @install \
|
||||
> && dune install --prefix install --display=short 2>&1 | dune_cmd sanitize )
|
||||
Installing install/lib/external_library/META
|
||||
Installing install/lib/external_library/correction.h
|
||||
Installing install/lib/external_library/dune-package
|
||||
Installing install/lib/external_library/extlib$ext_lib
|
||||
Installing install/lib/external_library/extlib.cma
|
||||
Installing install/lib/external_library/extlib.cmi
|
||||
Installing install/lib/external_library/extlib.cmt
|
||||
Installing install/lib/external_library/extlib.cmx
|
||||
Installing install/lib/external_library/extlib.cmxa
|
||||
Installing install/lib/external_library/extlib.ml
|
||||
Installing install/lib/external_library/opam
|
||||
Installing install/lib/external_library/extlib.cmxs
|
||||
|
||||
$ echo "(lang dune 2.1)" > some/dir/dune-project
|
||||
$ cat >some/dir/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name clib)
|
||||
> (language c)
|
||||
> (include_dirs (lib answer) (lib external_library))
|
||||
> (names src))
|
||||
> (executable
|
||||
> (modes exe)
|
||||
> (name main)
|
||||
> (foreign_archives clib)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ cat >some/dir/src.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> #include "header.h"
|
||||
> #include "correction.h"
|
||||
> value answer(value unit) { return Val_int((ANSWER + CORRECTION) * 2); }
|
||||
> EOF
|
||||
|
||||
$ export OCAMLPATH=$PWD/external/install/lib; dune exec ./main.exe --root=some/dir
|
||||
Entering directory 'some/dir'
|
||||
Leaving directory 'some/dir'
|
||||
Answer = 42
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* External library directories in (include_dir ...)
|
||||
* Build fails when using an unknown library
|
||||
|
||||
$ cat >some/dir/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name clib)
|
||||
> (language c)
|
||||
> (include_dirs (lib answer) (lib unknown_lib))
|
||||
> (names src))
|
||||
> (executable
|
||||
> (modes exe)
|
||||
> (name main)
|
||||
> (foreign_archives clib)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ rm -rf _build
|
||||
$ dune exec some/dir/main.exe
|
||||
File "some/dir/dune", line 4, characters 33-44:
|
||||
4 | (include_dirs (lib answer) (lib unknown_lib))
|
||||
^^^^^^^^^^^
|
||||
Error: Library "unknown_lib" not found.
|
||||
-> required by _build/default/some/dir/src.o
|
||||
-> required by _build/default/some/dir/libclib.a
|
||||
-> required by _build/default/some/dir/main.exe
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error when using path separators in an archive name
|
||||
|
||||
$ mkdir -p github2914/dir
|
||||
$ echo "(lang dune 2.1)" > github2914/dir/dune-project
|
||||
$ cat >github2914/dir/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name some/path/id)
|
||||
> (language c)
|
||||
> (names src))
|
||||
> EOF
|
||||
|
||||
$ dune build --root=github2914/dir
|
||||
Entering directory 'github2914/dir'
|
||||
File "dune", line 2, characters 15-27:
|
||||
2 | (archive_name some/path/id)
|
||||
^^^^^^^^^^^^
|
||||
Error: Path separators are not allowed in archive names.
|
||||
Leaving directory 'github2914/dir'
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Using (foreign_archives dir/id) in a (library ...), see #2914
|
||||
|
||||
$ mkdir -p github2914/dir
|
||||
|
||||
$ cat >github2914/dir/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name id)
|
||||
> (language c)
|
||||
> (names src))
|
||||
> EOF
|
||||
|
||||
$ cat >github2914/dir/src.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value id(value unit) { return Val_int(2914); }
|
||||
> EOF
|
||||
|
||||
$ cat >github2914/dune <<EOF
|
||||
> (library
|
||||
> (name bug)
|
||||
> (foreign_archives dir/id)
|
||||
> (modules bug))
|
||||
> (executable
|
||||
> (name main)
|
||||
> (modes byte exe)
|
||||
> (libraries bug)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ cat >github2914/bug.ml <<EOF
|
||||
> external id : unit -> int = "id"
|
||||
> let fix = Printf.sprintf "Bug #%d has been fixed" (id ())
|
||||
> EOF
|
||||
|
||||
$ cat >github2914/ticket.mli <<EOF
|
||||
> val fix : string
|
||||
> EOF
|
||||
|
||||
$ cat >github2914/main.ml <<EOF
|
||||
> let () = Printf.printf "%s\n" Bug.fix;
|
||||
> EOF
|
||||
|
||||
$ dune exec github2914/main.exe
|
||||
Bug #2914 has been fixed
|
||||
|
||||
$ dune build @github2914/all
|
||||
$ (cd _build/default/github2914 && ocamlrun -I dir main.bc)
|
||||
Bug #2914 has been fixed
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Make sure the [Byte_with_stubs_statically_linked_in] mode works too
|
||||
|
||||
$ cat >dune-workspace <<EOF
|
||||
> (lang dune 2.0)
|
||||
> (context
|
||||
> (default (disable_dynamically_linked_foreign_archives true)))
|
||||
> EOF
|
||||
|
||||
$ cat >github2914/dune <<EOF
|
||||
> (library
|
||||
> (name bug)
|
||||
> (foreign_archives dir/id)
|
||||
> (modules bug))
|
||||
> (executable
|
||||
> (name main)
|
||||
> (modes byte)
|
||||
> (libraries bug)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ dune clean
|
||||
$ dune exec github2914/main.exe
|
||||
Bug #2914 has been fixed
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
* Make sure that foreign stubs referencing code in foreign libs works too
|
||||
|
||||
$ mkdir -p stubs_in_libs
|
||||
$ cat >stubs_in_libs/dune-project <<EOF
|
||||
> (lang dune 2.5)
|
||||
> EOF
|
||||
$ cat >stubs_in_libs/lib.h <<EOF
|
||||
> extern int foo(void);
|
||||
> EOF
|
||||
$ cat >stubs_in_libs/lib.c <<EOF
|
||||
> int foo(void) { return 12; }
|
||||
> EOF
|
||||
$ cat >stubs_in_libs/stubs.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> #include "lib.h"
|
||||
> value bar(value unit) { return Val_int(foo()); }
|
||||
> EOF
|
||||
$ cat >stubs_in_libs/main.ml <<EOF
|
||||
> external bar: unit -> int = "bar" [@@noalloc]
|
||||
> let () = print_endline (string_of_int (bar ()))
|
||||
> EOF
|
||||
$ cat >stubs_in_libs/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name lib)
|
||||
> (language c)
|
||||
> (names lib))
|
||||
>
|
||||
> (executable
|
||||
> (name main)
|
||||
> (foreign_archives lib)
|
||||
> (foreign_stubs (language c) (names stubs)))
|
||||
> EOF
|
||||
$ dune build --root stubs_in_libs
|
||||
Entering directory 'stubs_in_libs'
|
||||
Leaving directory 'stubs_in_libs'
|
||||
$ stubs_in_libs/_build/default/main.exe
|
||||
12
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
* Test (enabled_if)
|
||||
|
||||
$ mkdir -p enabled_if
|
||||
$ cat >enabled_if/dune-project <<EOF
|
||||
> (lang dune 3.13)
|
||||
> EOF
|
||||
$ cat >enabled_if/lib.c <<EOF
|
||||
> int foo(void) { return 0; }
|
||||
> EOF
|
||||
$ cat >enabled_if/dune <<EOF
|
||||
> (foreign_library
|
||||
> (archive_name lib)
|
||||
> (language c)
|
||||
> (enabled_if (<> %{env:ENABLE=} "0"))
|
||||
> (names lib))
|
||||
> EOF
|
||||
$ dune build --root enabled_if
|
||||
Entering directory 'enabled_if'
|
||||
File "dune", line 4, characters 1-37:
|
||||
4 | (enabled_if (<> %{env:ENABLE=} "0"))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Error: 'enabled_if' is only available since version 3.14 of the dune
|
||||
language. Please update your dune-project file to have (lang dune 3.14).
|
||||
Leaving directory 'enabled_if'
|
||||
[1]
|
||||
$ cat >enabled_if/dune-project <<EOF
|
||||
> (lang dune 3.14)
|
||||
> EOF
|
||||
$ cat >>enabled_if/dune <<EOF
|
||||
> (library
|
||||
> (name lib)
|
||||
> (foreign_archives lib))
|
||||
> EOF
|
||||
$ ENABLE=1 dune build --root enabled_if
|
||||
Entering directory 'enabled_if'
|
||||
Leaving directory 'enabled_if'
|
||||
$ ENABLE=0 dune build --root enabled_if
|
||||
Entering directory 'enabled_if'
|
||||
File "dune", lines 6-8, characters 0-45:
|
||||
6 | (library
|
||||
7 | (name lib)
|
||||
8 | (foreign_archives lib))
|
||||
Error: No rule found for liblib.a
|
||||
Leaving directory 'enabled_if'
|
||||
[1]
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
Error when specifying an (archive_name ...) in (foreign_stubs ...) stanza.
|
||||
|
||||
$ echo "(lang dune 2.0)" > dune-project
|
||||
$ ./sandboxed.sh
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name foo)
|
||||
> (foreign_stubs (archive_name baz) (language c) (names foo))
|
||||
> (foreign_archives bar))
|
||||
> (rule
|
||||
> (targets bar%{ext_obj})
|
||||
> (deps bar.c)
|
||||
> (action (run %{ocaml-config:c_compiler} -c -I %{ocaml-config:standard_library} -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets libbar_stubs.a)
|
||||
> (deps bar%{ext_obj})
|
||||
> (action (run ar rcs %{targets} %{deps})))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "dune", line 3, characters 16-34:
|
||||
3 | (foreign_stubs (archive_name baz) (language c) (names foo))
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
Error: The field "archive_name" is not allowed in the (foreign_stubs ...)
|
||||
stanza. For named foreign archives use the (foreign_library ...) stanza.
|
||||
[1]
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
----------------------------------------------------------------------------------
|
||||
Testing the building of bytecode executables with foreign archives.
|
||||
|
||||
$ echo "(lang dune 2.0)" > dune-project
|
||||
$ ./sandboxed.sh
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Fails to build a pure bytecode executable with a foreign archive
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (executable
|
||||
> (modes byte)
|
||||
> (name main)
|
||||
> (modules main)
|
||||
> (foreign_archives time))
|
||||
> (foreign_library
|
||||
> (archive_name time)
|
||||
> (language c)
|
||||
> (names time))
|
||||
> EOF
|
||||
|
||||
$ cat >time.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value current_time(value unit) { return Val_int(1345); }
|
||||
> EOF
|
||||
|
||||
$ cat >main.ml <<EOF
|
||||
> external current_time : unit -> int = "current_time"
|
||||
> let () = Printf.printf "clock = %d" (current_time ())
|
||||
> EOF
|
||||
|
||||
$ dune clean
|
||||
$ dune exec ./main.bc
|
||||
File "dune", lines 1-5, characters 0-80:
|
||||
1 | (executable
|
||||
2 | (modes byte)
|
||||
3 | (name main)
|
||||
4 | (modules main)
|
||||
5 | (foreign_archives time))
|
||||
Error: Pure bytecode executables cannot contain foreign archives.
|
||||
Hint: If you only need to build a native executable use "(modes exe)".
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Build a bytecode executable by statically linking in a foreign archive when the
|
||||
setting [disable_dynamically_linked_foreign_archives] is [true] in the workspace
|
||||
|
||||
$ cat >dune-workspace <<EOF
|
||||
> (lang dune 2.0)
|
||||
> (context
|
||||
> (default (disable_dynamically_linked_foreign_archives true)))
|
||||
> EOF
|
||||
|
||||
$ dune clean
|
||||
$ dune exec ./main.bc
|
||||
clock = 1345
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Make sure no rules are generated for foreign dynamically linked archives
|
||||
|
||||
$ dune build _build/default/dlltime.so
|
||||
Error: Don't know how to build _build/default/dlltime.so
|
||||
[1]
|
||||
|
||||
'
|
||||
----------------------------------------------------------------------------------
|
||||
* Fails to install a library with foreign stubs when a [dll*.so] rule is missing
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 1.11)
|
||||
> (package
|
||||
> (name foo))
|
||||
> EOF
|
||||
|
||||
$ cat >dune-workspace <<EOF
|
||||
> (lang dune 2.0)
|
||||
> (context
|
||||
> (default (disable_dynamically_linked_foreign_archives false)))
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (public_name foo.clock)
|
||||
> (name clock)
|
||||
> (modules clock)
|
||||
> (self_build_stubs_archive (time)))
|
||||
> (rule
|
||||
> (targets time%{ext_obj})
|
||||
> (deps time.c)
|
||||
> (action (run %{ocaml-config:c_compiler} -c -I %{ocaml-config:standard_library} -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets libtime_stubs.a)
|
||||
> (deps time%{ext_obj})
|
||||
> (action (run ar rcs %{targets} %{deps})))
|
||||
> EOF
|
||||
|
||||
$ cat >clock.ml <<EOF
|
||||
> external current_time : unit -> int = "current_time"
|
||||
> let clock = current_time ()
|
||||
> EOF
|
||||
|
||||
$ cat >clock.mli <<EOF
|
||||
> val clock : int
|
||||
> EOF
|
||||
|
||||
$ dune clean
|
||||
$ dune build @install
|
||||
File "dune", lines 1-5, characters 0-100:
|
||||
1 | (library
|
||||
2 | (public_name foo.clock)
|
||||
3 | (name clock)
|
||||
4 | (modules clock)
|
||||
5 | (self_build_stubs_archive (time)))
|
||||
Error: No rule found for dlltime_stubs.so
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Succeeds to install a library with foreign stubs when a [dll*.so] rule is missing
|
||||
but the setting [disable_dynamically_linked_foreign_archives] is [true] in the workspace
|
||||
|
||||
$ cat >dune-workspace <<EOF
|
||||
> (lang dune 2.0)
|
||||
> (context
|
||||
> (default (disable_dynamically_linked_foreign_archives true)))
|
||||
> EOF
|
||||
|
||||
$ dune clean
|
||||
$ dune build @install
|
||||
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
----------------------------------------------------------------------------------
|
||||
Compatability testsuite for the (foreign_stubs ...) field.
|
||||
|
||||
$ ./sandboxed.sh
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error when using both (self_build_stubs_archive ...) and (c_names ...) before 2.0.
|
||||
|
||||
$ echo "(lang dune 1.0)" > dune-project
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name foo)
|
||||
> (c_names foo)
|
||||
> (self_build_stubs_archive (bar)))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "dune", line 4, characters 1-33:
|
||||
4 | (self_build_stubs_archive (bar)))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Error: A library cannot use (self_build_stubs_archive ...) and (c_names ...)
|
||||
simultaneously. This is supported starting from Dune 2.0.
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error when using (c_names ...) in (library ...) in Dune 2.0.
|
||||
|
||||
$ echo "(lang dune 2.0)" > dune-project
|
||||
|
||||
$ dune build
|
||||
File "dune", line 3, characters 1-14:
|
||||
3 | (c_names foo)
|
||||
^^^^^^^^^^^^^
|
||||
Error: 'c_names' was deleted in version 2.0 of the dune language. Use the
|
||||
(foreign_stubs ...) field instead.
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error when using (c_names ...) in (executable ...) in Dune 2.0.
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (executable
|
||||
> (name foo)
|
||||
> (c_names bar))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "dune", line 3, characters 2-9:
|
||||
3 | (c_names bar))
|
||||
^^^^^^^
|
||||
Error: Unknown field "c_names"
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error when using (self_build_stubs_archive ...) in (library ...) in Dune 2.0.
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name foo)
|
||||
> (foreign_stubs (language c) (names foo))
|
||||
> (self_build_stubs_archive (bar)))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "dune", line 4, characters 1-33:
|
||||
4 | (self_build_stubs_archive (bar)))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Error: 'self_build_stubs_archive' was deleted in version 2.0 of the dune
|
||||
language. Use the (foreign_archives ...) field instead.
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error when using (self_build_stubs_archive ...) in (executable ...) in Dune 2.0.
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (executable
|
||||
> (name foo)
|
||||
> (foreign_stubs (language c) (names bar))
|
||||
> (self_build_stubs_archive (baz)))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "dune", line 4, characters 2-26:
|
||||
4 | (self_build_stubs_archive (baz)))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Error: Unknown field "self_build_stubs_archive"
|
||||
[1]
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
----------------------------------------------------------------------------------
|
||||
|
||||
* Error when a C source file is missing.
|
||||
|
||||
$ ./sandboxed.sh
|
||||
$ echo "(lang dune 2.0)" > dune-project
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name foo)
|
||||
> (foreign_stubs (language c) (names foo))
|
||||
> (foreign_archives bar))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "dune", line 3, characters 36-39:
|
||||
3 | (foreign_stubs (language c) (names foo))
|
||||
^^^
|
||||
Error: Object "foo" has no source; "foo.c" must be present.
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Error when a self-built archive is missing.
|
||||
|
||||
$ cat >foo.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value foo(value unit) { return Val_int(9); }
|
||||
> EOF
|
||||
|
||||
$ dune build 2>&1 | dune_cmd sanitize
|
||||
File "dune", lines 1-4, characters 0-87:
|
||||
1 | (library
|
||||
2 | (name foo)
|
||||
3 | (foreign_stubs (language c) (names foo))
|
||||
4 | (foreign_archives bar))
|
||||
Error: No rule found for libbar$ext_lib
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Build succeeds when a self-built archive exists.
|
||||
|
||||
$ cat >bar.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value bar(value unit) { return Val_int(10); }
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name foo)
|
||||
> (foreign_stubs (language c) (names foo))
|
||||
> (foreign_archives bar))
|
||||
> (rule
|
||||
> (targets bar%{ext_obj})
|
||||
> (deps bar.c)
|
||||
> (action (run %{ocaml-config:c_compiler} -c -I %{ocaml-config:standard_library} -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets libbar.a)
|
||||
> (deps bar%{ext_obj})
|
||||
> (action (run ar rcs %{targets} %{deps})))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
Testsuite for the (foreign_stubs ...) field.
|
||||
|
||||
$ echo "(lang dune 3.0)" > dune-project
|
||||
$ ./sandboxed.sh
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Foreign stubs in C and C++ language.
|
||||
* Multiple foreign stub archives.
|
||||
|
||||
$ cat >baz.cpp <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> extern "C" value baz(value unit) { return Val_int(0); }
|
||||
> EOF
|
||||
|
||||
$ cat >qux.cpp <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> extern "C" value qux(value unit) { return Val_int(2000); }
|
||||
> EOF
|
||||
|
||||
$ cat >foo.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value foo(value unit) { return Val_int(9); }
|
||||
> EOF
|
||||
|
||||
$ cat >bar.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> value bar(value unit) { return Val_int(10); }
|
||||
> EOF
|
||||
|
||||
$ cat >quad.ml <<EOF
|
||||
> external foo : unit -> int = "foo"
|
||||
> external bar : unit -> int = "bar"
|
||||
> external baz : unit -> int = "baz"
|
||||
> external qux : unit -> int = "qux"
|
||||
> let quad x = foo x + bar x + baz x + qux x
|
||||
> EOF
|
||||
|
||||
$ cat >quad.mli <<EOF
|
||||
> val quad : unit -> int
|
||||
> EOF
|
||||
|
||||
$ cat >main.ml <<EOF
|
||||
> let () = Printf.printf "%d" (Quad.quad ())
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name quad)
|
||||
> (modules quad)
|
||||
> (foreign_stubs (language c) (names foo))
|
||||
> (foreign_archives bar qux)
|
||||
> (foreign_stubs (language cxx) (names baz)))
|
||||
> (rule
|
||||
> (targets bar%{ext_obj})
|
||||
> (deps bar.c)
|
||||
> (action (run %{cc} -c -I %{ocaml-config:standard_library} -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets libbar.a)
|
||||
> (deps bar%{ext_obj})
|
||||
> (action (run ar rcs %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets dllbar%{ext_dll})
|
||||
> (deps bar%{ext_obj})
|
||||
> (action (run %{cc} -shared -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets qux%{ext_obj})
|
||||
> (deps qux.cpp)
|
||||
> (action (run %{cxx} -c -I %{ocaml-config:standard_library} -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets libqux.a)
|
||||
> (deps qux%{ext_obj})
|
||||
> (action (run ar rcs %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets dllqux%{ext_dll})
|
||||
> (deps qux%{ext_obj})
|
||||
> (action (run %{cc} -shared -o %{targets} %{deps})))
|
||||
> (executable
|
||||
> (name main)
|
||||
> (modes exe byte)
|
||||
> (libraries quad)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
|
||||
$ dune exec ./main.exe
|
||||
2019
|
||||
|
||||
$ (cd _build/default && ocamlrun -I . ./main.bc)
|
||||
2019
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Unused foreign sources are ignored.
|
||||
|
||||
$ touch foo.cpp
|
||||
$ touch foo.cxx
|
||||
|
||||
$ dune build
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Fails when (extra_deps ...) is missing
|
||||
|
||||
$ cat >foo.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> #include "eight.h"
|
||||
> value foo(value unit) { return Val_int(1 + EIGHT); }
|
||||
> EOF
|
||||
|
||||
$ dune build 2> /dev/null
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Succeeds when (extra_deps ...) is present
|
||||
|
||||
$ cat >eight.h <<EOF
|
||||
> #define EIGHT 8
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name quad)
|
||||
> (modules quad)
|
||||
> (foreign_stubs (language c) (names foo) (extra_deps eight.h))
|
||||
> (foreign_archives bar qux)
|
||||
> (foreign_stubs (language cxx) (names baz)))
|
||||
> (rule
|
||||
> (targets bar%{ext_obj})
|
||||
> (deps bar.c)
|
||||
> (action (run %{cc} -c -I %{ocaml-config:standard_library} -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets libbar.a)
|
||||
> (deps bar%{ext_obj})
|
||||
> (action (run ar rcs %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets dllbar%{ext_dll})
|
||||
> (deps bar%{ext_obj})
|
||||
> (action (run %{cc} -shared -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets qux%{ext_obj})
|
||||
> (deps qux.cpp)
|
||||
> (action (run %{cxx} -c -I %{ocaml-config:standard_library} -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets libqux.a)
|
||||
> (deps qux%{ext_obj})
|
||||
> (action (run ar rcs %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets dllqux%{ext_dll})
|
||||
> (deps qux%{ext_obj})
|
||||
> (action (run %{cc} -shared -o %{targets} %{deps})))
|
||||
> (executable
|
||||
> (name main)
|
||||
> (modes exe byte)
|
||||
> (libraries quad)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ dune exec ./main.exe
|
||||
2019
|
||||
|
||||
$ (cd _build/default && ocamlrun -I . ./main.bc)
|
||||
2019
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Fails when (include_dirs ...) is missing
|
||||
|
||||
$ cat >foo.c <<EOF
|
||||
> #include <caml/mlvalues.h>
|
||||
> #include "eight.h"
|
||||
> #include "another/dir/one.h"
|
||||
> value foo(value unit) { return Val_int(ONE + EIGHT); }
|
||||
> EOF
|
||||
|
||||
$ dune build 2> /dev/null
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Succeeds when (include_dirs ...) is present
|
||||
|
||||
$ mkdir -p another/dir
|
||||
$ cat >another/dir/one.h <<EOF
|
||||
> #define ONE 1
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name quad)
|
||||
> (modules quad)
|
||||
> (foreign_stubs (language c) (names foo) (extra_deps eight.h) (include_dirs another/dir))
|
||||
> (foreign_archives bar qux)
|
||||
> (foreign_stubs (language cxx) (names baz)))
|
||||
> (rule
|
||||
> (targets bar%{ext_obj})
|
||||
> (deps bar.c)
|
||||
> (action (run %{cc} -c -I %{ocaml-config:standard_library} -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets libbar.a)
|
||||
> (deps bar%{ext_obj})
|
||||
> (action (run ar rcs %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets dllbar%{ext_dll})
|
||||
> (deps bar%{ext_obj})
|
||||
> (action (run %{cc} -shared -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets qux%{ext_obj})
|
||||
> (deps qux.cpp)
|
||||
> (action (run %{cxx} -c -I %{ocaml-config:standard_library} -o %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets libqux.a)
|
||||
> (deps qux%{ext_obj})
|
||||
> (action (run ar rcs %{targets} %{deps})))
|
||||
> (rule
|
||||
> (targets dllqux%{ext_dll})
|
||||
> (deps qux%{ext_obj})
|
||||
> (action (run %{cc} -shared -o %{targets} %{deps})))
|
||||
> (executable
|
||||
> (name main)
|
||||
> (modes exe byte)
|
||||
> (libraries quad)
|
||||
> (modules main))
|
||||
> EOF
|
||||
|
||||
$ dune exec ./main.exe
|
||||
2019
|
||||
|
||||
$ (cd _build/default && ocamlrun -I . ./main.bc)
|
||||
2019
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Fails when using standard names in foreign stubs due to multiple C++ sources
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name quad)
|
||||
> (modules quad)
|
||||
> (foreign_stubs (language cxx)))
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "dune", line 4, characters 1-31:
|
||||
4 | (foreign_stubs (language cxx)))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Error: Multiple sources map to the same object name "foo":
|
||||
- foo.cpp
|
||||
- foo.cxx
|
||||
This is not allowed; please rename them or remove "foo" from object names.
|
||||
Hint: You can also avoid the name clash by placing the objects into different
|
||||
foreign archives and building them in different directories. Foreign archives
|
||||
can be defined using the (foreign_library ...) stanza.
|
||||
[1]
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
* Succeeds when using a subset of standard names
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (library
|
||||
> (name quad)
|
||||
> (modules quad)
|
||||
> (foreign_stubs
|
||||
> (language cxx)
|
||||
> (names :standard \ foo)))
|
||||
> EOF
|
||||
|
||||
$ dune clean
|
||||
$ dune build
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
(executable
|
||||
(name main)
|
||||
(modes byte)
|
||||
(libraries hello_world))
|
||||
|
|
@ -0,0 +1 @@
|
|||
(lang dune 3.0)
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
(library
|
||||
(name hello_world)
|
||||
(foreign_stubs
|
||||
(language cxx)
|
||||
(names foreign_hello_world)))
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#include <iostream>
|
||||
|
||||
extern "C" void hello_world ();
|
||||
|
||||
void hello_world ()
|
||||
{
|
||||
std::cout << "Hello World!";
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
external hello_world : unit -> unit = "hello_world"
|
||||
|
|
@ -0,0 +1 @@
|
|||
Hello_world.hello_world ();;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Building a cxx library should run ocamlmklib with the correct link flags for
|
||||
gcc (-lstdc++) and clang (-lc++). In case of failure this test will print a
|
||||
series of "undefined symbols" errors for various elements of the c++ std.
|
||||
$ dune build
|
||||
|
||||
On windows this test should always pass because no specific flag is needed for
|
||||
msvc to link with the standard library.
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#include "caml/mlvalues.h"
|
||||
|
||||
value caml_b_or_n(value unit)
|
||||
{
|
||||
#ifdef NATIVE_CODE
|
||||
return Val_int(1);
|
||||
#else
|
||||
return Val_int(0);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#include "caml/mlvalues.h"
|
||||
|
||||
value caml_b_and_n(value unit)
|
||||
{
|
||||
return Val_int(0);
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
(executable
|
||||
(modes native byte_complete)
|
||||
(modules stubs_exe)
|
||||
(name stubs_exe)
|
||||
(foreign_stubs
|
||||
(language c)
|
||||
(mode byte)
|
||||
(names c_stubs))
|
||||
(foreign_stubs
|
||||
(language c)
|
||||
(mode native)
|
||||
(flags :standard -DNATIVE_CODE)
|
||||
(names c_stubs)))
|
||||
|
||||
(executable
|
||||
(modes native byte_complete)
|
||||
(modules stubs_lib)
|
||||
(name stubs_lib)
|
||||
(libraries mode_dep_stubs))
|
||||
|
||||
(executable
|
||||
(modes native byte_complete)
|
||||
(modules stubs_same_exe)
|
||||
(name stubs_same_exe)
|
||||
(foreign_stubs
|
||||
(language c)
|
||||
(names c_stubs_same)))
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#include "caml/mlvalues.h"
|
||||
|
||||
value caml_b_or_n(value unit)
|
||||
{
|
||||
#ifdef NATIVE_CODE
|
||||
return Val_int(1);
|
||||
#else
|
||||
return Val_int(0);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
(library
|
||||
(name mode_dep_stubs)
|
||||
(foreign_stubs
|
||||
(language c)
|
||||
(mode byte)
|
||||
(names c_stubs_lib))
|
||||
(foreign_stubs
|
||||
(language c)
|
||||
(mode native)
|
||||
(flags :standard -DNATIVE_CODE)
|
||||
(names c_stubs_lib)))
|
||||
|
|
@ -0,0 +1 @@
|
|||
external stub_byte_or_native : unit -> int = "caml_b_or_n"
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
##############
|
||||
Project Toggle
|
||||
##############
|
||||
|
||||
Without the toggle, we get an error message for using the new mode subfield
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 3.5)
|
||||
> EOF
|
||||
|
||||
$ dune build 2>&1 | head -n 6
|
||||
File "dune", line 11, characters 3-16:
|
||||
11 | (mode native)
|
||||
^^^^^^^^^^^^^
|
||||
Error: 'mode' is available only when mode_specific_stubs is enabled in the
|
||||
dune-project file. You must enable it using (using mode_specific_stubs 0.1)
|
||||
in your dune-project file.
|
||||
|
||||
But the toggle only exists in Dune 3.5
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 3.1)
|
||||
> (using mode_specific_stubs 0.1)
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
File "dune-project", line 2, characters 27-30:
|
||||
2 | (using mode_specific_stubs 0.1)
|
||||
^^^
|
||||
Error: Version 0.1 of syntax extension for mode-specific foreign stubs is not
|
||||
supported until version 3.5 of the dune language.
|
||||
There are no supported versions of this extension in version 3.1 of the dune
|
||||
language.
|
||||
|
||||
[1]
|
||||
|
||||
With Dune 3.5 no error is displayed
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 3.5)
|
||||
> (using mode_specific_stubs 0.1)
|
||||
> EOF
|
||||
|
||||
$ dune build
|
||||
$ dune clean
|
||||
|
||||
###########
|
||||
Executables
|
||||
###########
|
||||
|
||||
Native executables should output 1, others 0 if they have mode-dependent stubs
|
||||
$ dune exec ./stubs_exe.exe
|
||||
Byte (0) or native (1) ? 1
|
||||
|
||||
$ dune exec ./stubs_exe.bc.exe
|
||||
Byte (0) or native (1) ? 0
|
||||
|
||||
But stubs_same_exe which does not have mode dependent stubs and should
|
||||
always output 0
|
||||
$ dune exec ./stubs_same_exe.exe
|
||||
Byte (0) and native (0) ? 0
|
||||
|
||||
$ dune exec ./stubs_same_exe.bc.exe
|
||||
Byte (0) and native (0) ? 0
|
||||
|
||||
There should be two different object files for the mode-dependent stub `c_stub`
|
||||
but only one for the non-mode-dependent stub `c_stub_same`
|
||||
$ ls _build/default/*.o
|
||||
_build/default/c_stubs_byte.o
|
||||
_build/default/c_stubs_native.o
|
||||
_build/default/c_stubs_same.o
|
||||
|
||||
$ dune clean
|
||||
|
||||
#########
|
||||
Libraries
|
||||
#########
|
||||
|
||||
|
||||
|
||||
$ dune exec ./stubs_lib.exe
|
||||
Byte (0) or native (1) ? 1
|
||||
|
||||
$ dune exec ./stubs_lib.bc.exe
|
||||
Byte (0) or native (1) ? 0
|
||||
|
||||
|
||||
$ dune clean
|
||||
|
||||
Now we try will being in the sandbox
|
||||
$ cat >sdune <<'EOF'
|
||||
> #!/usr/bin/env bash
|
||||
> DUNE_SANDBOX=symlink dune "$@"
|
||||
> EOF
|
||||
$ chmod +x sdune
|
||||
|
||||
$ ./sdune exec ./stubs_exe.exe
|
||||
Byte (0) or native (1) ? 1
|
||||
|
||||
$ ./sdune exec ./stubs_exe.bc.exe
|
||||
Byte (0) or native (1) ? 0
|
||||
|
||||
$ ./sdune exec ./stubs_lib.exe
|
||||
Byte (0) or native (1) ? 1
|
||||
|
||||
$ ./sdune exec ./stubs_lib.bc.exe
|
||||
Byte (0) or native (1) ? 0
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
external stub_byte_or_native : unit -> int = "caml_b_or_n"
|
||||
|
||||
let () = Printf.printf "Byte (0) or native (1) ? %i\n" (stub_byte_or_native ())
|
||||
|
|
@ -0,0 +1 @@
|
|||
let () = Printf.printf "Byte (0) or native (1) ? %i\n" (Mode_dep_stubs.stub_byte_or_native ())
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
external stub_byte_and_native : unit -> int = "caml_b_and_n"
|
||||
|
||||
let () = Printf.printf "Byte (0) and native (0) ? %i\n" (stub_byte_and_native ())
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
(executable
|
||||
(name stubs_exe)
|
||||
(modes native byte_complete)
|
||||
(libraries stubs_lib stubs_liboth))
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
(lang dune 3.5)
|
||||
(using mode_specific_stubs 0.1)
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#include "caml/mlvalues.h"
|
||||
|
||||
value caml_b_or_n(value unit)
|
||||
{
|
||||
#ifdef NATIVE_CODE
|
||||
return Val_int(1);
|
||||
#else
|
||||
return Val_int(0);
|
||||
#endif
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue