OCamlbuild not resolving subdirectory dependency - ocaml

I have an OCaml project and I'm running into a weird issue.
The directory structure looks like this:
./tests
test.ml
templatetest.ml
./src
template.ml
...
andsoforth.ml
I am building it like this:
ocamlbuild -Is src,tests tests/test.native
Key point being, tests/test.ml depends on tests/templatetest.ml.
When I build it, I get:
+ /usr/local/bin/ocamlc.opt -c -I tests -I src -o tests/test.cmo tests/test.ml
File "tests/test.ml", line 1, characters 0-17:
Error: Unbound module TemplateTest
Command exited with code 2.
Compilation unsuccessful after building 2 targets (0 cached) in 00:00:00.
I tried adding a _tags file in the top directory containing:
<src> or <tests>: include
That still produced the same error. (I believe ocamlbuild tests/test.native with the _tags file is the exact same thing as the previous build line I used.)
I also created an empty _tags file in both ./tests and ./src, but that didn't change anything either.
Any suggestions? If you need, the entire source is here. Just run make test. Thanks!

It a funny issue: not TemplateTest but Templatetest. For the former name, you module file should be named templateTest.ml

Related

Compiling and Running Ocaml Script from the Terminal

I have files called assert.ml, assert.mli, test.ml and test.mli stored in a folder. assert is I guess you'd call it a library file--it's something I downloaded but didn't write myself. test.ml is a file containing the script
;; open Assert
;; print_endline "test"
In the terminal I navigate to the containing folder and run
$ ocamlc -c assert.mli test.mli
$ ocaml assert.ml test.ml
Nothing happens as a result. However, if I remove the ;; open Assert line from the script and run
$ ocaml test.ml
then it prints.
As a note, I've had some people tell me not to write the open command as ;; open Assert but the advice seems entirely stylistic. I have to write it this way for the class I'm taking.
If anyone can explain to me how I ought to be compiling and running differently I'd appreciate it. I tried following some other guides' advice in using ocamlopt instead but when I ran it, no executable file was produced as a result.
The ocaml command is the REPL for OCaml. The command line looks like this:
ocaml [ object-files ] [ script-file ]
An object file is a compiled (bytecode) module, which is produced by the ocamlc command. These files end with .cmo. A script file is a file of OCaml source code, which ends with .ml.
Note that only one script file is allowed.
The command you say you're using has two script files and no object files. So, it's not surprising that it doesn't work. In my experiments, what ocaml does is run just the first of the two script files. I believe this explains what you see. One of your files produces output, and it will be run if you give it first. The other produces no output, so there is no output when that file is given first.
What you should probably be doing is producing a .cmo file for the Assert module.
That would look like this:
$ ocamlc -c assert.mli assert.ml test.mli
Then you should run ocaml with one object file and one script file, like this:
$ ocaml assert.cmo test.ml

Using ocamlmktop with ocamlbuild

I have a project that builds successfully using ocamlbuild. However, I would also like an easy way to interact with the project's individual functions from different modules via the toplevel but my attempts at using ocamlmktop haven't worked out as I'd like. I've found that unless I manually put the .cmi files in the active directory, I get an "Unbound module" error. The command I'm currently using to build is:
ocamlfind ocamlmktop -I _build -o my_ocaml -linkpkg -package str module1.cmo module2.cmo
Is there a better, less hacky way to get the toplevel to work in this project structure without moving cmi files out of the _build directory?
Edit: I've figured out that I can get it to load the types and modules if I run the toplevel as
./my_ocaml -I _build
But this still seems hacky. Is there a way to bake the search path or cmi files in perhaps?
Edit 2: I think the solution to my problem may actually be not to compile a custom toplevel at all given this restriction about interface files. I have instead added load directives to my .ocamlinit to use the modules. If anybody has better ideas to solve this, I'd greatly appreciate it.
You can build a toplevel by listing the module names you want in a my_ocaml.mltop file:
Module1
Module2
subdir/Module3
Then building the target my_ocaml.top will call ocamlmktop in the expected way, and you can run the resulting my_ocaml.top toplevel.
This does not change the way that you need to add _build to the include path for the type-checker to be able to find the .cmi files. You can do this when you invoke the toplevel by passing the command-line arguments -I _build, or from the toplevel with #dir "_build";; -- the last command can also be put in your .ocamlinit if you prefer.

Ocamldoc and open modules

I'm trying to document a small project of mine using ocamldoc.
I have one main .ml file which opens two others .ml files.
$ ocamldoc -html included1.ml included2.ml
Works just fine, but when I add the including file, like
$ ocamldoc -html included1.ml included2.ml including.ml
I get this:
File "including.ml", line 5, characters 5-16:
Error: Unbound module Included1
1 error(s) encountered
I see from the ocamldoc documentation that opening modules is perfectly fine, until no conflict arises.
How should I proceed?
It's fine for a module to use other modules however it needs to be able to see the compiled interfaces for those. So in your case you first need to compile the .ml files to generate .cmi files. Then you need to indicate to ocamldoc where these files are. So something like this should do:
ocamlc -c included1.ml
ocamlc -c included2.ml
ocamlc -c -I . including.ml
ocamldoc -html -I . included1.ml included2.ml including.ml
Note that in general it's a good (essential) practice to create .mli files for each of your modules an document and ocamldoc these rather than the .ml files.

Why can't scons find my project's source files?

Here's my project on github.
Here's my SConstruct file:
SConscript('main.scons', variant_dir = 'build', duplicate = 0)
Here's my main.scons file:
import sys
import os
import fnmatch
def find_source_files(directory, ext = "cpp"):
matches = []
for root, dirnames, filenames in os.walk(directory):
for filename in fnmatch.filter(filenames, '*.' + ext):
matches.append(os.path.join(root, filename))
return matches
if __name__ == '__main__':
for f in find_source_files('src'):
print f
else:
Program(target = 'main.bin', source = find_source_files('src'))
Here's what I get when I run it:
bitcycle # cypher ~/git/IeiuniumTela $ find $(pwd) -name "*.bin" -or -name "*.o" -exec rm {} \;; scons; find $(pwd) -name "*.bin" -or -name "*.o"
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: building associated VariantDir targets: build
gcc -o build/main.bin
gcc: fatal error: no input files
compilation terminated.
scons: *** [build/main.bin] Error 4
scons: building terminated because of errors.
Here's what happens when I run `python main.scons' to test it:
bitcycle # cypher ~/git/IeiuniumTela $ python main.scons
src/main.cpp
I'm having a hard time understanding why it can't find my source files. Any suggestions or ideas here?
[UPDATE] After getting some good direction from the mailing list, I found that this worked "good enough" for me.
/SConstruct: SConscript('src/main.scons', variant_dir = 'build', duplicate = 0)
/src/main.scons: Program(target = 'main.bin', source = Glob('*.cpp'))
See the github repository for the full source tree. I've also added an empty build directory to the repo for completeness. I find it interesteding that:
a. SCons' version of Glob isn't recursive, in the context of this build tool for discovering source. I would expect that a recursive discovery option is preferred. :(
b. I need to put the scons file in the same directory as the source file (which is annoying).
c. Print statements apparently work, but sys.stdout.write doesn't (from the python module).
Could it be because your main.scons file is already in the src directory, and your find_source_file is actually searching src/src?
It found the source sources for me when I moved the scons files to the top directory.
Update:
Upon investigation, variant_dir sets the working directory to build, so your find_source_files looks for files in build/src and finds nothing. Would be probably better to either call find_source_files from the SConstruct file, or to use VariantDir() inside main.scons instead.
SCons treats relative directory paths differently from Python, so I wouldnt be surprised to see a difference between the test execution and the SCons execution. Typically in SCons everything is relative to the root SConstruct script, or the SConscript script.
Your code appears correct, but how about adding some debugging print statements in find_source_files() to find out exactly what's happening?
Perhaps you plan to use the find_source_files() function more extensively later on, but for the simple case of one source file, it seems like you are over complicating things and you could just use the following in main.scons:
Program(target = 'main.bin', source = 'src/main.cpp')

Can't get cygwin to compile C++ Boost libraries

I'm trying to get up and running with Boost, so I'm trying to compile the simple example problem from Boost's "Getting Started" page. I've had two issues, and I'm not sure they're related (I'm better than a novice, but not by much) but maybe they're related...
1st issue: the "tar --bzip2 -xf /path/to/boost_1_49_0.tar.bz2" command didn't work (yes, I put the correct path in, but it gave me some errors, I forget what they were) so I used "tar -xjvf " from the directory where boost_1_49_0.tar.bz2 was located. That de-compressed the zip file and I proceeded with the example...
2nd issue: The example.cpp file will not compile, the first statement in the code is #include "boost/lambda/lambda.hpp" but then for every header file lambda.hpp is trying access, there's a "No such file or directory" compile error. For example, here are two (of the six, and I get errors for all 6) header files within lambda.hpp and the errors displayed by the cygwin compiler:
boost/lambda/lambda.hpp:14:33: boost/lambda/core.hpp: No such file or directory
boost/lambda/lambda.hpp:21:52: boost/lambda/detail/operator_actions.hpp: No such file or directory
If it helps, this is the command I'm running to compile (I generally create the executable in a separate -o command):
g++ -c example.cpp
Why can't the system find these? I added the installed directory (path/to/boost_1_49_0) to the PATH variable before I started so I know that's no it. Thanks for any advice...
(I've looked on stackoverflow and there were similar issues, but no solutions that worked)
It looks like you've already solved the first issue: namely, that you must specify the -j flag on tar to untar a bzip2'd file.
For the second issue, you need to specify boost on your include path, either by specifying it with the -I command line option or via the CPLUS_INCLUDE_PATH environment variable.