Where to place a shared utility module in OCaml? - module

I have a file Tools.ml which contains some common utility functions I write myself. Under .../Code/ I have several folders which each contains a project. My question is where I should place this Tools.ml such that all the folders and files under .../Code/ could share this module by Open Tools.
Hope my question is clear... Does anyone have a good solution?
Edit1: Following #gasche's answer, I have written tools.ml as follows:
module Tools =
struct
let a_function = ...
...
end
Then I compiled it, and done ocamlfind install tools META tools.cmo tools.cmx tools.ml as suggested, which looks going well. Then I have written test.ml as follows:
open Tools
let f = Tools.a_function
then I compiled it with ocamlc test.ml -o test, then I got an error:
File "test.ml", line 1, characters 0-1:
Error: Error while linking test.cmo:
Reference to undefined global `Tools'
Could anyone tell me what happened?

You could package it as an independent library, install it with other OCaml libraries, and access to it, from your project, as a library.
A very simple way to do this is to write a META file for ocamlfind. Create a directory somewhere you're comfortable to hold you "personal library" project. Suppose you have tools.ml and tools.mli, and your code depends on some findlib package (eg. unix and bigarray). You META would look like this:
name="tools"
description="personal collection of utilities"
version="0.1"
requires="unix,bigarray"
archive(byte)="tools.cmo"
archive(native)="tools.cmx"
Once you have written this META file, it is easy to ask ocamlfind to "install" the library (and remove it if you want to), and use it in your other projects. To install, the syntax is ocamlfind install <name> <meta-file> <file1> <file2> ... where <file1>, <file2>.. are the file you wish to see included in the installation directory. You must at least have tools.cmi tools.cmo (and tools.o and tools.cmx for native compilation), but it is good practice to also have tools.mli for example (and, if you want to provide the code, tools.ml).
ocamlfind install tools META tools.cmi tools.cmo tools.o tools.cmx tools.mli
(Of course tools.cmo etc. have to exist, that is you must install after you have compiled your package. If you have used ocamlbuild, they are likely to be in a _build subdirectory, so ocamlfind install ... _build/tools.cmo ....)
From your numerous projects, you can use your library easily, either using the ocamlfind toold directly if this is what you already do to compile your programs
ocamlfind ocamlc -package tools ....
or through the facilities provided by ocamlbuild for example, adding package(tools) to your tags.
To reinstall your library if you made a change to it and want it accessible from your projects
ocamlfind remove tools
ocamlfind install tools META ...
You could also handle all this through oasis, which is a layer on top of ocamlfind/ocamlbuild to automate this process. I'm not familiar enough with oasis to give such examples off the top of my head, but it should be equally simple for such a restricted case (one-file library), and scale better if you wish later to extend your library (eg. it can also handle documentation generation, pre-compilation configuration...).

Related

How can you use multiple modules in a Raku project, if the modules are defined in the project?

I'm playing around with writing modules in Raku, when it made sense for me to break a piece of functionality off into another .rakumod file. How can I link these files together when I compile?
I tried to pull the other module to my main module via:
use MyProject::OtherModule;
But I get an error that it can't find this module even though they're side by side in the directory. I tried looking at some OSS projects in the Raku world, most of them are one file, the compiler Rakudo seems to use multiple module files but I can't figure out how they're linked.
Do I have to publish this module every time I want to run my project? How do I structure this if my project gets huge? Surely the best solution isn't to have it all in one file?
Edit: I should also note that I used this at the top of my new module too:
unit module MyProject::OtherModule;
When running locally, if you have your META6.json declared, you can use
raku -I. script.raku
and it will use the uninstalled versions, and you don't need to add any use lib in the script.

When I should use find_package

I am learning CMake, and I feel hard to understand when I should use find_package.
For separate compilation, we need to let the compiler knows where to find the header file, and this could be done by target_include_directories. For linking, we need to let the linker knows where the implementation is, and this could be done by target_link_libraries. It seems like that is all we need to do to compile a project. Could anyone explain why and when we should use find_package?
If a package you intend allows for the use of find_package, you should use it. If a package comes with a working configuration script, it'll encourage you to use the library the way it's intended to be used likely come with a simple way to add include directories and dependencies required.
When is it possible to use find_package?
There needs to be either a configuration script (<PackageName>Config.cmake or packagename-config.cmake) that gets installed with the package or find script (Find<PackageName>.cmake). The latter one in some cases even comes with the cmake installation instead of the package installed, see CMake find modules.
Should you create missing scripts yourself?
There are several benefits in creating a package configuration script yourself, even if a package doesn't come with a existing configuration or find script:
The scripts separate the information about libraries from the logic used to create your own target. The use of the 2 commands find_package and target_link_libraries is concise and any logic you may need to collect and apply information like dependencies, include directories, minimal versions of the C++ standard to use, ect. would probably take up much more space in your CMakeLists.txt files thus making it harder to understand.
If makes library used easy to replace. Basically all it takes to go with a different version of the same package would be to modify CMAKE_PREFIX_PATH, CMAKE_MODULE_PATH or package-specific <PackageName>_ROOT variables. If you ever want to try out different versions of the same library, this is incredibly useful.
The logic is reuseable. If you need to use the same functionality in a different project, it takes little effort to reuse the same logic. Even if a library is only used within a single project, but in multiple places, the use of find_package can help keeping the logic for "importing" a lib close to its use (see also the first bullet point).
There can be multiple versions of the same library with automatic selection of applicable ones. Note that this requires the use of a version file, but this file allows you to specify, if a version of the package is suitable for the current project. This allows for the checking the target architecture, ect. This is helpful when cross compiling or when providing both 32 and 64 bit versions of a library on Windows: If a version file indicates a mismatch the search for a suitable version simply continues with different paths instead of failing fatally when considering the first mismatch.
You will probably find CMake's guide on using dependencies helpful. It describes find_package and alternatives, and when each one is relevant / useful. Here's an excerpt from the section on find_package (italics added):
A package needed by the project may already be built and available at some location on the user's system. That package might have also been built by CMake, or it could have used a different build system entirely. It might even just be a collection of files that didn't need to be built at all. CMake provides the find_package() command for these scenarios. It searches well-known locations, along with additional hints and paths provided by the project or user. It also supports package components and packages being optional. Result variables are provided to allow the project to customize its own behavior according to whether the package or specific components were found.
find_package requires that the package provide CMake support in the form of specific files that describe the package's contents to CMake. Some library authors provide this support (the most desirable scenario for you, the package consumer), some don't but are prominent enough that CMake itself comes with such files for those packages, or in the worst case, there is no CMake support at all, in which case you can either do something to get the either of the previous good outcomes, or perform some kludges to get the job done (ie. define the targets yourself in your project's CMake config).

Install files using symbolic links with CMAKE

I have converted my project to use cmake. During development I'd like to be able to install the product not the normal way, but let (notably) the installed data files be symbolic links to the source tree.
The project is SWI-Prolog which provides functionality to directly navigate and edit source files. If I use this to extend and fix the system libraries however I'm editing the installed copy that I then need to copy back to the sources before I can commit.
I know I can override functions in cmake, but in this case we are dealing with cmake code that is generated.

Where to install FindLib.cmake

I'm creating a library (called fmi2) which I intend to install on my local machine (via a package manager) and then link to with a bunch of other libraries.
I'll be providing a Findfmi2.cmake file so that I can call find_package(fmi2) from my other libraries, but where should this file be conventionally installed?
Here are some choices I've considered and their problems:
/usr/share/cmake-3.8/Modules/Findfmi2.cmake
Advantage: find_package(fmi2) will just work
Disadvantage: Only works for one version of cmake
/usr/share/cmake/Modules/Findfmi2.cmake
Advantage: Should work for any version of cmake
Disadvantage: This is not a default folder. We would need to add set(CMAKE_MODULES_PATH /usr/share/cmake/Modules) and this kills any portability.
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Findfmi2.cmake
Advantage: Portable, just need to add set(CMAKE_MODULES_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
Disadvantage: Not system-wide. Need to manually add this file to each library that uses it. This duplicates files in my framework.
You are authoring content in CMake. You don't need a FindModule. That is designed to find external non-CMake outputs.
This Stackoverflow post from ruslo should help you understand the difference between find_package() module mode and config mode. It also answers your question about paths for FindModules, i.e. they are copied into your CMake project, not discovered system-wide, unless they are part of the official FindModules bundled with CMake in the "Modules" directory.
Modern CMake documentation now finally contains good examples to create a config mode package: cmake-packages
If you want explicit full examples, though using slightly older syntax for the config.cmake files, ruslo has more on Github.

How to create project file in Free Pascal IDE?

I'm started to learn Free Pascal and stick to the simple yet important question: is it possible to create project in console Free Pascal IDE?
How could I compile two units into one program?
I've searched over Internet, but all links leads to the Lazarus, which is not the same thing as Free Pascal IDE...
My best clue would be is to use Makefiles, but as far as I can see, information on this is also very-very limited.
So how create and compile multi-unit Pascal programs in Free Pascal IDE then?
The textmode IDE has no project concept where a list of files is kept, OR any external build system.
Basically the autobuild capability of the compiler (that is built-in) is utilized, so pressing compile or build on the mainmodule(program) will compile the whole lot.
The main module can be set in compiler->primary file, so that compile will also work from non main modules.
However it is possible to have local IDE settings (primary file, directories, defines), by copying all fp.(cfg|dsk|ini) files from the FPC directory to your project dir, and then customizing them (from within the IDE).
One could regard the combination of a set of config files + a directory for the mainmodule as a project or solution.