OCaml: using Oasis with multiple-level src folders - ocaml

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.

Related

CMake with 3rd party libraries that need to be built along with the project

I am confused on the right way to get an external library integrated into my own Cmake project (This external project needs to be built along with my project, it's not installed separately, so we can't use find_library, or so I think)
Let's assume we have a project structure like this (simplified for this post):
my_proj/
--CMakeLists.txt
--src/
+---CMakeLists.txt
+---my_server.cpp
That is, we have a master CMakeLists.txt that basically sits at root and invokes CMakeLists for sub directories. Obviously, in this example, because its simplified, I'm not showing all the other files/directories.
I now want to include another C++ GitHub project in my build, which happens to be this C++ bycrypt implementation: https://github.com/trusch/libbcrypt
My goal:
While building my_server.cpp via its make process, I'd like to include the header files for bcrypt and link with its library.
What I've done so far:
- I added a git module for this external library at my project root:
[submodule "third_party/bcrypt"]
path = third_party/bcrypt
url = https://github.com/trusch/libbcrypt
So now, when I checkout my project and do a submodule update, it pulls down bcrypt to ${PROJ_ROOT}/third_party
Next up, I added this to my ROOT CMakeLists.txt
# Process subdirectories
add_subdirectory(third_party/bcrypt)
add_subdirectory(src/)
Great. I know see when I invoke cmake from root, it builds bcrypt inside third_party. And then it builds my src/ directory. The reason I do this is I assume this is the best way to make sure the bcrypt library is ready before my src directory is built.
Questions:
a) Now how do I correctly get the include header path and the library location of this built library into the CMakeLists.txt file inside src/ ? Should I be hardcoding #include "../third_party/bcrypt/include/bcrypt/bcrypt.h" into my_server.cpp and -L ../third_party/libcrypt.so into src/CMakeLists.txt or is there a better way? This is what I've done today and it works, but it looks odd
I have, in src/CMakeLists.txt
set(BCRYPT_LIB,"../third_party/bcrypt/libbcrypt.so")
target_link_libraries(my app ${MY_OTHERLIBS} ${BCRYPT_LIB})
b) Is my approach of relying on sequence of add_directory correct?
Thank you.
The best approach depends on what the bcrypt CMake files are providing you, but it sounds like you want to use find_package, rather than hard-coding the paths. Check out this answer, but there are a few different configurations for find_package: MODULE and CONFIG mode.
If bcrypt builds, and one of the following files gets created for you:
FindBcrypt.cmake
bcrypt-config.cmake
BcryptConfig.cmake
that might give you an idea for which find_package configuration to use. I suggest you check out the documentation for find_package, and look closely at how the search procedure is set up to determine how CMake is searching for bcrypt.

Undefined module when using Oasis to build an OCaml project

It's me, again.. I am working on an OCaml project and I would like to use Oasis to build the whole code base. Here is how my codebase is organized.
src/
core/
init.ml
type.ml
utils.ml
plugin/
main.ml
I firstly only build the library with the following _oasis file:
Library "engine"
Path: src/core
Modules:
Init,
Type,
Utils
BuildDepends: deriving, deriving.syntax, core, batteries
XMETADescription: core engine
And it works fine. There is no error and I can find a library engine.a in the _build/src/core folder.
However, when I try to include the library in the main.ml with the following way:
Module T = Engine.Type
...
And compile with the following _oasis file:
Library "engine"
Path: src/core
Modules:
Init,
Type,
Utils
BuildDepends: deriving, deriving.syntax, core, batteries
XMETADescription: core engine
Executable "main"
Path: src/plugin
MainIs: main.ml
CompiledObject: best
Install: false
BuildDepends: core, batteries, engine
I got an error:
Unbound module Engine
Am I doing anything wrong here? Could anyone give me some help? Thank you!
Your _oasis module defines a library with the name engine but it does not define an Engine module. So your Init, Type and Utils modules are exposed and should be accessible directly without any prefix.
If you want to pack those modules into a parent you can:
Manually pack each module into one big engine.ml file
Use Pack: true in the Library section of your _oasis file which would pack the included modules into a module called Engine
Use module aliases (see the OCaml manual for more information)

What is the best way of CMake in a Middle-sized Project?

In my company, we're developing a middle sized project which we plan to use CMake as the build platform generator. In this scenario, me and my colleagues were discussing about which way the CMake should be used. Our discussions came to a turn which we must decide the methods to use. Our directory structure is similar to this:
<"our project"> \
modules \
module_1 \
tests \
test_example.cpp
mock
some_mock_class.hpp
some_class.hpp
some_class.cpp
...
module_2 \
...
module_3 \
...
utility \
...
1- First thing is first, my colleague thinks that folders like "src" and "includes" are reminder of C programming and has no place in a modern C++ program, so we don't need them. So we removed them from the structure, but being a Linux guy; I'm not sure if this is a good idea. Should we set a "include" directory for headers, so CMake can install them appropriately to the include dirs of the install target; or can CMake handle them appropriately?
2- Should we make a CMakeLists.txt to the root of the project which includes and defines all the targets, or should we make a CMakeLists.txt per module, and then use "add_subdirectory" directives to include them? My colleague thinks on CMakeLists.txt is the best, because this way the module implementors don't need to think about CMake at all, and one or two admins of deployment can maintain the file; but I think every module implementor is more aware of which libraries they use, and how to compile their modules - which he disagrees. What do you suggest in this case?
If you did use CMake for such a middle-sized project before (or know of a case) can you please recommend us what they did and, if possible, why?
Sincerely
The topic is huge, but in short my personal recommendation. For a middle project I assime a component model should be already applied. Then reasonable then is, to have component directories with their onwn CMakeLists.txt which are referenced by the top-level CMakeLists.txt via add_subdirectory(). Each component - a separate library (I like static ones).
For the component folders I find reasonable to hide all internal stuff (aka implementation and private headers, ...) under a private sub-directory to do not be exposed to the outside. Then, in the top component directory you have only headers which are to be used by the others. In the private directory you can mix sources and headers - this is only a matter of the taste for mid projects. And the private directory can also be decomposed if the component is large. But then you need to decide either to add all artifacts to the single CMakeLists.txt of the component, or to have sub-libraries. But in that case the users should link to them individually instead to link to the component's library only.
In the best case, the folder structure should follow the dependencies structure and form a tree-view build system, where the components have as less knowlege about internals of the other components as possible. In that case you will have a good configurability and flexibility in case of possible refactorings. In the other words, the design of the build system seems to me similar to the class design in C++ - same principles.
The real (target) build directory where you run cmake can be located anywhere, normally outside of the source directory. A good place for it could be a RAM disc if you enough memory. Then for the clean build you need just to remove it, that's it. But the source and the build itself have no dependency from its location.
Ah yes, one more hint. My recommendation would be to include headers by the path starting from the component directory like #include "SomeHeader.hpp" which is located as ComponentX/SomeHeader.hpp. Then the CMakelists.txt is used to do the ComponentX directory known to your component. This means, the paths to the headers are not hardcoded in the source files. This brings some limitation like unique file names, but makes changes to the components location much easier.
Hope this anyhow helps.

The right way to structure my c++ project with cmake?

I have been struggling with this for quite a while, and my adventures with cmake have only resulted in hackish solutions that I am pretty sure are not correct.
I created a library that consists of several files, as follows:
-libfolder
-codepart1folder
-CMakeLists.txt
-codepart1.cpp
-codepart1.hpp
-codepart2folder
-codepart3folder
-lib.cpp
-lib.hpp
-CMakeLists.txt
I wrote a CMakeLists file to compile the library (after some experimentation), and I can generate a lib.a file. Now I would like to include this code as a library in other projects, and access it through the interface in lib.hpp. What is the best way to do this, in terms of directory structure, and what I need to put into CMakeLists.txt in my root project?
My current attempt has been to add -libfolder as a subfolder to my current project, and add the commands:
include_directories(${PROJECT_SOURCE_DIR}/libfolder)
link_directories(${PROJECT_BINARY_DIR}/libfolder)
add_subdirectory(libfolder)
target_link_libraries(project lib)
When I run make, the library compiles fine, but when project.cpp compiles, it complains that it cannot find codepart1.hpp (which is included in lib.hpp, included from project.cpp).
I suspect that this is the wrong way about doing this, but I cannot wade through the CMake documentation and find a good tutorial on setting up projects like this. Please help, CMake gurus!
The clean way to import one CMake project into another is via the find_package command. The package declaration is done by using the export command. An advantage of using find_package is that it eliminates the need to hard-code paths to the package's files.
Regarding the missing hpp file, you didn't include codepart1folder, so it's not on the include path.
Ok, so after consulting a coworker of mine who is a CMake guru, it seems CMake does not have support for what I am trying to do, leaving one with 3 options:
Add all of the dependencies to the parent projects CMakeLists.txt - not very clean, but it will get the thing to work. You'll have to do this for every project you add the code to, and go back and fix things if your library changes.
clean up your library headers. This is done through some compiler hackery. The idea is to forward-declare every class, and use only pointers or boost::shared_ptr, and then include the dependencies only in the cpp file. That way you can build the cpp file using all the findpackage stuff, and you get the bonus of being able to use the lib by only including the header and linking to the library.
Look into build systems. Having portable code and fast code compilation with complex dependencies is not a solved problem! From my investigations it turned out to be quite complicated. I ended up adopting my coworkers build system which he created himself in cmake, using things he picked up from Google.
Looking at your post you don't seem to add 'codepart1folder' to the includes anywhere. How are you including codepart1.hpp as:
#include <codepart1.hpp>
#include "codepart1folder/codepart1.hpp"
I don't think there is a standard accepted way to structure cmake projects. I've looked at a bunch of cmake repos and they tend to have differences. Personally I do the following:
-project
CMakeLists.txt
-build
-cmake
OptionalCmakeModule.cmake
-src
-Main
Main.cpp
Main.hpp
-DataStructs
SomeTree.hpp
SomeObject.hpp
-Debug
Debug.hpp
-UI
Window.hpp
Window.cpp
Basically that dumps all the source code into 1 directory, then you perform an out of source build with: 'mkdir build && cd build && cmake .. && make' in the projects root folder.
If you have separate libs as part of your project, then you might want a separate libs directory with another subfolder for your specific lib.
I have some of my repos on: https://github.com/dcbishop/ if you want to look at the CMakeLists.txt files.
The main problems with my project structure are that I use the FILE_GLOB which is apparently the 'wrong' way to do things (if you add files after running 'cmake ..' then they won't be picked up hen you do a 'make'). I haven't figured out what the 'right' way to do it is (from what I can see it involves keeping a separate list of files) I also only use 1 CMakeLists.txt file.
Some projects also choose to separate their cpp and hpp files into separate directories. So you would have an include and src folders (at least for the hpp files that are intended to be used externally). I think that would mainly be for projects that are mainly large libraries. Would also make installing header files much easier.
You are probably missing
include_directories(${PROJECT_SOURCE_DIR}/libfolder/codepart1folder)
In such a case you might want to set( CMAKE_INCLUDE_CURRENT_DIR on) to add all folders to the include directory path variable.
Check cmake's output on the command line whether the correct include folders are set or not. Additionally you can always use message() as "print debugging" for cmake variables.
In case of include directories however you need to read the directory property to see what is actually in the include directories.
get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
message("inc_dirs = ${inc_dirs}")
I hope this helps you figuring out what is missing.
Edit
I just saw your comment about added codepart1folder in the libfolder. It is only available in the libfolder's include_directory path and not propagated to the root folder.
Since the include codepart1.hpp is present in the lib.hpp however you need to have it also available in the project path otherwise you will get missing declaration errors when you build your project.

Using "ocamlfind" to make the OCaml compiler and toplevel find (project specific) libraries

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