Is it possible to dune utop mylib load a library in "promiscuous mode" which would ignore the .mli interface files and expose the internals, like values or types not listed as part of the public interface?
In effect, loading utop "from within" the implementation, and not "from outside", issuing standard open commands with abstraction enforced by the public interface.
This is not possible. You can open a ticket on the github repository of dune to ask for such a feature.
Related
Background
I'm trying to expose two dune libraries from the same directory - one for some interfaces, and the other for their implementations.
For example, let's say I have the following sources:
foo_api.ml
module type Foo = sig
val foo: string
end
foo.ml
module FooImpl: Foo =
let foo = "foo"
end
In my dune file, I want to expose these as separate libraries - an API and an implementation. I'd really like to be able to use globs here to specify the modules, as I'm planning on using this pattern for other modules, eg. Bar.ml and Bar_api.ml.
Question
Does dune support some way of globbing (or regex'ing) for modules?
(library
(name foo_lib_api)
(modules (glob_files "./*_api.ml")))
(library
(name foo_lib_implementation)
(modules (:standard \ (glob_files "./*_api.ml"))))
The above syntax does not work, and I haven't found anything that does work. Perhaps I'm trying to use dune like I would use bazel, which would let me use glob or filegroup.
Dune does not support glob patterns in the modules stanza.
A more idiomatic alternative would be to have one directory, which has the advantages of allowing to decouple the module and library names.
In .NET I can decorate my assembly with the following attribute:
[<assembly: InternalsVisibleTo("MyProject.Test")>]
Thanks to this, all the modules marked as "internal" are accessible from "MyProject.Test". I can use it e.g. for unit testing the functionality I don't want to expose in my library.
I'm wondering if there's something similar in the Haskell's world. Let's say I have a library with the following .cabal file:
library
exposed-modules: MyLibrary.API
other-modules: MyLibrary.Utils
-- ...
test-suite mylib-test
-- ...
build-depends: base,
hspec,
my-library
Is there a way to refer to "MyLibrary.Utils" from mylib-test test-suite?
You can make it part of an internal library, and depend on that from both the public library and the test suite. It will not be available outside the package.
library utils
exposed-modules: MyLibrary.Utils
library
exposed-modules: MyLibrary.API
build-depends: utils
test-suite mylib-test
build-depends: base, hspec, my-library, utils
Alternately, there's a strong convention of exposing the module anyway, but including Internal in its name and telling folks in the documentation that you break it you bought it.
I am trying to use oasis to compile my project, and my project is organized in this way:
_oasis
src/
main.ml
core_a.ml
core_b.ml
type.ml
plugins/
plugin_a.ml
plugin_b.ml
Note that in the plugin_a.ml, it refers to module type.ml (i.e., open Type).
When I use oasis to compile the project, it reports:
Unbound module Type
Here is the simplified version of my _oasis file:
....
BuildTools: ocamlbuild
BuildDepends: deriving, deriving.syntax, core, batteries
Executable "main"
Path: src
MainIs: main.ml
CompiledObject: best
Install: false
BuildDepends: deriving, deriving.syntax, core, batteries
Am I doing anything wrong here? Or what I am doing is not the best practice to organize a project like this?
I think your project structure is a bit strange. You have a sub directory for plugins, but you should note that there's no namespace or package hierarchy so this is not really useful in practice.
As for whether this is possible, the answer seems to be mixed:
It's not possible to do it with just oasis because it doesn't let you specify multiple values for the Path option.
It should be easily done with ocamlbuild however by tagging everything you need with include (but I don't recommend this).
As your oasis project grows, you should look into defining library sections in oasis and using those to organize inter project dependencies. E.g., in this case you could create a "plugins" library where you include plugin_a and plugin_b. But without some planning ahead here, you will quickly run into circular dependencies.
In our workflow, we can have a module A that is composed of several header files, module A not producing any binary (side note: it will obviously be used by other modules, that include some of the headers from module A to produce binaries).
A good example would be a header-only library, for which CMake 3 introduces a good support thanks to the notion of INTERFACE library (see this SO answer, and CMake's documentation of the feature).
We can make an interface library target out of module A:
add_library(module_A INTERFACE)
That gives us all the nice features of CMakes targets (it is possible to use it as another target's dependency, to export it, to transitively forward requirements etc.)
But in this case, the headers in module A do not show up in our IDE (Xcode, yet we expect it to be the same with most/every other IDE).
This proves to be a major drawback in the workflow, since we need the files composing module A to be shown in the IDE for edition. Is it possible to achieve that ?
Several months down the line, I did not find a way to directly list the header files for an INTERFACE library.
Since the question still has some views, here is what I ended up doing (i.e. what appears like the lesser hack currently available).
Imagine module A is a header only library. In the CMakeLists.txt declaring its target:
# Define 'modA_headers' variable to list all the header files
set(modA_headers
utility.h
moreUtilities.h
...)
add_library(moduleA INTERFACE) # 'moduleA' is an INTERFACE pseudo target
#
# From here, the target 'moduleA' can be customised
#
target_include_directories(moduleA ...) # Transitively forwarded
install(TARGETS moduleA ...)
#
# HACK: have the files showing in the IDE, under the name 'moduleA_ide'
#
add_custom_target(moduleA_ide SOURCES ${modA_headers})
I do not accept this answer, since I expect further releases of CMake to offer a more semantically correct approach, which will then be accepted : )
You can use the new target_sources command in CMake 3.1.
add_library(moduleA INTERFACE)
target_include_directories(moduleA INTERFACE ...)
target_sources(moduleA INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/utility.h
${CMAKE_CURRENT_SOURCE_DIR}/moreUtilities.h
)
It is also transitive.
http://www.cmake.org/cmake/help/v3.1/command/target_sources.html#command:target_sources
The limitation of not being able to export targets which have INTERFACE_SOURCES has been lifted for CMake 3.3.
I'm trying to use ocamlfind with both the OCaml compiler and toplevel. From what I understood, I need to place the required libraries in the _tags file at the root of my project, so that the ocamlfind tool will take care of loading them - allowing me to open them in my modules like so :
open Sdl
open Sdlvideo
open Str
Currently, my _tags file looks like this :
<*>: pkg_sdl,pkg_str
I can apparently launch the ocamlfind command with the ocamlc or ocamlopt argument, provided I wan't to compile my project, but I did not see an option to launch the toplevel in the same manner. Is there any way to do this (something like "ocamlfind ocaml")?
I also don't know how to place my project specific modules in the _tags file : imagine I have a module name Land. I am currently using the #use "land.ml" directive to open the file and load the module, but it has been suggested that this is not good practice. What syntax should I use in _tags to specify it should be loaded by ocamlfind (considering land.ml is not in the ocamlfind search path) ?
Thank you,
Charlie P.
Edit : According to the first answer of this post, the _tags file is not to be used with ocamlfind. The questions above still stand, there is just a new one to the list : what is the correct way to specify the libraries to ocamlfind ?
try this:
$ cat >> .ocamlinit
#use "topfind";;
#require "sdl";;
#require "sdlvideo";;
open Sdl
open Sdlvideo;;
open Str;;
.ocamlinit is sourced from the current directory, falling back to /home/user/.ocamlinit. you can explicitly override it via ocaml -init <filename>
One should distinguish ocamlfind packages, module names and file names. Source code references only module names. Modules are provided by .cma .cmo .cmx (and .cmi) files. Ocamlfind packages are named collections of such files (binaries built from some ocaml library sources). Ocamlfind is not strictly necessary to build a project - just specify the paths to all used libraries via -I. But if the project is distributed in source form - another people will have troubles building it cause used libraries are placed in different places. Then one seeks the way to specify the names of used "third party code pieces" and some external tool to resolve those names to actual paths. This tool is ocamlfind.
First find the ocamlfind package that provides the modules you need (in this case Sdl and Sdlvideo - just run ocamlfind list, most probably the package is named sdl.
Compile with ocamlfind ocamlc -package <package name> -linkpkg source.ml -o program
Alternatively use ocamlfind to extract the path to the .cma file (and others) provided by the package (ocamlfind query <package name>) and use this path with your build tool (plain Makefile, ocamlbuild, etc).
Moreover ocamlfind (is intended to) take away the burden of remembering how the actual .cma files are named and what matching compiler options are required and in what order the packages are depending on each other. One just needs to specify the package name.
Keep in mind that there is no one-to-one strict formal relationship between library name (purely human-targeted name e.g. ocaml-extlib), module names (ExtLib, Enum, IO, etc), file names (extLib.cma) and ocamlfind package name (extlib), though for convenience package maintainers and library authors usually choose guessable names :)
The _tags file is not for ocamlfind, but for ocamlbuild.
Exemple :
ocamlbuild land.native