I have a .ml file, I would like to generate its .cmo, .cmx, .cmi and .mli by as least commands as possible, could anyone help?
I don't think there's any way to generate all these files at once.
.mli : ocamlc -i x.ml > x.mli
.cmi : ocamlc x.mli
.cmo : ocamlc -c x.ml
.cmx : ocamlopt -c x.ml
If you can do without the .mli file, you can generate the .cmi and .cmo files together with ocamlc -c. Otherwise I think you'll have to generate files one at a time.
Note that there is a .o file for every .cmx file; they work as a pair.
You can use a Makefile to do all this for you. I have an example project template here that might help: https://github.com/snim2/ocaml-template
Say make byte, make native or make docs to generate the sort of output you're looking for.
Related
Consider the following setup:
$ touch 1.src 2.src 3.src
$ cat Makefile
%.dst: %.src
#convert -o "$#" "$<"
We can compile our .src files into .dst files by running make 1.dst 2.dst 3.dst which calls the convert (just a placeholder) tool three times.
This setup is fine if there is little overhead in calling convert. However, in my case, it has a startup penalty of a few seconds for every single call. Luckily, the tool can convert multiple files in a single call while paying the startup penalty only once, i.e. convert -o '{}.dst' 1.src 2.src 3.src.
Is there a way in GNU make to specify that multiple src files should be batched into a single call to convert?
Edit: To be more precise, what feature I am looking for: Say that 1.dst is already newer than 1.src so it doesn't need to be recompiled. If I run make 1.dst 2.dst 3.dst, I would like GNU make to execute convert -o '{}.dst' 2.src 3.src.
A quick and dirty way would be creating a .PHONY rule that simply converts all src files to dst files but that way I would convert every src file each and every time. Further more, specifying dst files as prerequisites in other rules would also no longer be possible.
Thanks in advance!
If you have GNU make 4.3 or above, you can use grouped targets like this:
DST_FILES = 1.dst 2.dst 3.dst
SRC_FILES = $(_DST_FILES:.dst=.src)
all: $(DST_FILES)
$(DST_FILES) &: $(SRC_FILES)
convert -o '{}.dst' $?
#touch $(DST_FILES)
If your convert is only updating some of the targets then you need the explicit touch to update the rest.
Here's a way to do it with passing a goal on the command line that might work; change DST_FILES to:
DST_FILES := $(or $(filter %.dst,$(MAKECMDGOALS)),1.dst 2.dst 3.dst)
Is there a way in GNU make to specify that multiple src files should be batched into a single call to convert?
It is possible, but messy, to write make rules for build steps that produce multiple targets with a single run of the recipe, such that the recipe is executed just once if any of the targets needs to be updated. However, you clarify that
[if] 1.dst is already newer than 1.src [, and] I run make 1.dst 2.dst 3.dst, I would like GNU make to execute convert -o '{}.dst' 2.src 3.src.
. That's a slightly different problem. You can use the $? automatic variable in a recipe to get the prerequisites that are newer than the rule's target, but for that to serve the purpose, you need a rule with a single target.
Here's one slightly convoluted way to make it work:
DST_FILES = 1.dst 2.dst 3.dst
SRC_FILES = $(DST_FILES:.dst=.src)
$(DST_FILES): dst.a
ar x $< $#
dst.a: $(SRC_FILES)
convert -o '{}.dst' $?
x='$?'; ar cr $# $${x//src/dst}
The dst.a archive serves as the one target with all the .src files as prerequisites, so as to provide a basis for use of $?. Additionally, it provides a workaround for the problem that whenever that target is updated, it becomes newer than all the then-existing .dst files: .dst files that are out of date with respect to the archive but not with respect to the corresponding .src file are extracted from the archive instead of being rebuilt from scratch.
I use GCC to create dependency files, from header files stored in a
certain directory. Here is my recipe:
gcc -MM -MG -MT obj/$*.o -MP -MF dep/$*.Td -I include $<
One of these header files is generated (with Bison 3.0.5), so it may not
exist. I therefore use the -MG option as shown above, but it generates
a dependency without the directory. How can I tweak make or GCC to
prepend the include directory to the generated header?
Thanks in advance
dordow
Typically, the search path has many entries, and if the header file does not exist, it is unclear which prefix to pick.
The cook build tool comes with a program, c_incl, which scans C source files for #include directives and can be made to behave in the way you intend, with a command like c_incl -No_Cache -Absent_System_Mention -Iinclude -C. But this tool is fairly obscure.
It is probably better to use a slightly less obscure GNU make feature instead: order-only prerequisites, as described in Types of Prerequisites. You would list the generated header files (or other Bison output files) as order-only prerequisites for all rules that compile C files, so that they are generated early on first build, but do not needlessly trigger rebuilds afterwards. With this approach, you do not need to generate dependencies on files which do not exist yet.
In a simple embedded project, i have two files main.rs and module.rs. To build the project, I use something similar to this:
all: main.o
$(CC) main.o $(LDFLAGS)
%.o: %.rs
$(RUSTC) $(RUSTFLAGS) -o ${#} ${<}
If only module.rs is changed, make all won't recompile my Rust code. How can I fix this?
I'm posting a suboptimal self-answer as a first step, but would love to see better ways.
The best way to use Make is to encode every single dependency into the Makefile. That's what gives Make the power to know what to rebuild in order to reach a goal state.
To do this for a C project, you'll often use something like the GCC command line option -M. This brings the compiler into the mix as it's the best tool to parse C source code and understand the dependencies between the
files.
There is actually an equivalent switch for rustc, the Rust compiler: --emit=dep-info. When you run this on a source file, it will output a file with the extension .d, which contains an almost-Makefile-compatible list of dependencies. If you had a main.rs that referenced the module foo.rs, it would output something like:
main.d: main.rs foo.rs
With a bit of sed tweaking you can get this to play nicely. You can then include this in your Makefile:
main.o:
rustc -o $# $<
main.d: main.rs
rustc --emit=dep-info $<
# Add the object file as a rule
gsed 's/:/ $(#:.d=.o):/' -i $#
-include main.d
Here, I've specified main in a few parts, but I believe that you can easily modify them into pattern rules.
The pragmatic solution is to just use Cargo, the Rust build tool and package manager. Let it deal with dependencies (both local modules and other crates).
libbar.dylib: target/debug/libbar.dylib
cp $< $#
.PHONY: target/debug/libbar.dylib
target/debug/libbar.dylib:
cargo build --verbose
Here, I've marked the rule as PHONY, which says "always run this rule". I've added --verbose to have Cargo print out what it is doing so you can verify when things are rebuilt.
I'd recommend dropping off the cp step if you can and instead just use the nested path, but the copy might be needed if other things rely on the current location.
The pattern
%.o: %.rs
is familiar from building C projects, but that's not the only way a target can be written. Specific to the setup above, this would fix the situation:
main.o: main.rs module.rs
$(RUSTC) $(RUSTFLAGS) -o main.o main.rs
A noteworthy difference to the original code is that the names of the inputs is not really what matters for the command. We can generalize this as follows:
main.o: $(wildcard *.rs)
$(RUSTC) $(RUSTFLAGS) -o ${#} ${#:.o=.rs}
This is a start, but it still has some downsides I couldn't get rid of:
The main.o: part is hardcoded. If there are multiple top-level modules to compile, there would be code duplication
All Rust files will be considered for all top-level modules, due to the wildcard. In other words, changing any Rust file will require a full recompilation.
I was experimenting with GNU make. Suppose, I have 3 C files with the following structure:
hellomake.c
|
|---------------------
| |
V V
hellofunc.c hellomake.h
makefile:
hellomake: hellomake.c hellofunc.c
gcc -o hellomake hellomake.c hellofunc.c -I.
When I type make for the 1-st time, it creates a program hellomake. When I run it for the 2-nd time, it prints:
make: `hellomake' is up to date.
Everything is working correctly.
I tried to use make for compiling LaTeX files. Suppose, I have 2 TeX files:
1.tex
|
V
1_data.tex
1_data is included into 1.tex internally.
Makefile:
COMMAND = pdflatex
all: 1.tex 1_data.tex
$(COMMAND) 1.tex
But it recompiles 1.tex every time I type make. Even if none of the files were modified.
What's wrong?
makesimply looks at whether or not all exists. Since it doesn't, it attempts to create it (but doesn't even notice that your commands do not create the file!)
Assuming pdflatex really creates a file somewhere, use the file name as the target name. Then it will be recreated only if it is older than the dependencies.
To recapitulate, a Makefile declares a mapping of target files, their dependencies, and how to create them from the dependencies. When a target is missing or out of date with respect to its dependencies, Make runs the commands for recreating it.
(My first attempt at articulating this answer mentioned .PHONY: targets as an aside, but that's not really useful in this context; if you declared .PHONY: all it would run the recipe even if a file named all existed, so that's the opposite behavior of what you are looking for.)
When I call protoc like this
protoc --cpp_out=. path/to/test.proto
the files
path/to/test.pb.cc and
path/to/test.pb.h
are generated which is what I want. But, since the cc needs the h, the h is included like this
#include "path/to/test.pb.h"
which is not what I want. The background is that my build tool (scons) calls protoc from the project's root and not from the directory which includes the source files. I found no obvious option in the manpage or the help text.
So my next idea was to consider this as "correct" and adjust my build system, but: The two files are siblings in the directory tree, so when one includes the other, no path is needed. Even compiling by hand fails.
Can someone help me with that?
Doing find-replace on generated files is most likely easier
than reorganization of your build system (use sed command on Linux/unix).
What I ended up doing for my project is as follows:
Create a pb/ directory at the same level as your include/ and src/ directories.
Put your .proto files in there, and create a makefile. Write the following in it:
CXX = g++
CXXFLAGS = -O3
PROTOBF = $(shell find ./ -name '*.proto')
SOURCES = $(subst proto,pb.cc,$(PROTOBF))
OBJECTS = $(subst proto,pb.o,$(PROTOBF))
default: $(OBJECTS)
#echo -n
$(SOURCES): %.pb.cc : %.proto
protoc --cpp_out=. $<
$(OBJECTS): %.pb.o : %.pb.cc
$(CXX) $(CXXFLAGS) -c $< -o $#
Which will essentially generate and build the protobuffer files when invoked.
In your main makefile, simply add the following include path: -Ipb/.
And when including a protocol buffer header, use #include <whatever.pb.h>.
Add the object files generated in pb/ to your linking step. Myself I used:
PB_OBJS = $(shell find pb/ -name '*.pb.o')
And gave that to the linker along with the normal object files in obj/.
Then, you can probably call the pb/ makefile from the main makefile if you want to automate it. The important point is that protoc be called from the pb/ directory or the include will be messed up.
Sorry for the ugly makefiles. At least it works, and I hope this helps you...