How to include library with meson? - c

I want to add the INHI library (which use meson too) to my project but I don't know how to.
The project tree :
Project/
- meson.build
- src/
- - meson.build
- - inih/
- - main.c
The root meson.build contains :
project('test', 'c')
subdir('src')
src/meson.build
executable('main', 'main.c')
What do I have to add in the meson.build for using inih in main.c ?
Thank you !

Meson has a concept of subprojects.
Create a subprojects directory on the top level of your project (The same level where you have meson.build).
Create a wrap file for your dependency inside the subprojects directory and name it inih.wrap with content:
[wrap-git]
url = https://github.com/benhoyt/inih
revision = head
this tells meson to use git to get a dependency.
In your meson.build integrate inih as dependency like this:
inih_sp = subproject('inih')
inih_dep = inih_sp.get_variable('inih_dep')
...
executable('main', 'main.c',dependencies:[inih_dep])
EDIT:
The other way is to use wrap-file instead of wrap-git. In this case, only the second item would change. Simply find your library here and put it in the subprojects directory.
For more information, check Wrap dependency system manual

Related

Load a resource file at runtime

Suppose I have this architecture:
.
├── Cargo.lock
├── Cargo.toml
├── src/
│ ├── main.rs
├── rsc/
│ ├── file.xml
I want to load file.xml to fill some tables at each run. To do so I could write:
use std::fs::File;
use std::path::Path;
fn open<P: AsRef<Path>>(path: P) {
let _ = File::open(path).unwrap();
println!("file opened");
}
fn main() {
open("../rsc/file.xml");
}
But the relative path won't work if I don't run the program from src.
I could do the following:
fn main() {
include_str!("../rsc/file.xml");
}
But this will be done at compile time meaning that changing file.xml means recompiling the program so it's completely unsafe in terms of maintainability.
The other option I can see is giving the rsc path as an argument to my program but I find it a bit cumbersome since this is not an optional argument, I really need to know where my rsc directory is and I know my crate will have this architecture.
Is there something I can't see?
I saw this post: How to avoid hard-coded values in Rust
But my question is summarized in this part:
If you are deploying a binary, you may have to supply a path to where your application should find its resources.
And there's no other precision about it.
You can find the path to your binary using std::env::current_exe(). You can use this to find the directory that the binary is in, and then use that to load some resource relative to this directory.
For instance if your resources were in a directory 'rsrc' which was in the same directory as your binary:
let mut rsrc_dir = std::env::current_exe()
.expect("Can't find path to executable");
// Directory containing binary
rsrc_dir.pop();
// Subdir relative to binary
rsrc_dir.push("rsrc");
This would only be useful if your binary is installed with its resource files in some fixed location relative to the binary. Keep in mind that most users will not be cloning your crate from github and running it that way - typical methods for installation would include:
installing it with cargo install
using some OS specific package manager
perhaps downloading a tar or zip file and decompressing it
It seems that cargo install does not currently handle installing associated resource files (although there is an open bug for that).

In waf, how do I define a dependency on a generated header from another subdir

I am trying to get waf to generate header files generated by a task chain and pick up on them automatically using the c preprocessor's scan function.
Here is an example project. Some files get generated in the project's gen directory, to be used in the project's `prog' directory.
The layout:
├── gen
│   ├── test.txt
│   └── wscript
├── prog
│   ├── main.c
│   └── wscript
├── waf
└── wscript
The generation of the .h file happens through a task chain declared in the top-level file:
top = '.'
def configure(cfg):
cfg.load('compiler_c')
def build(bld):
from waflib import TaskGen
TaskGen.declare_chain(name = 'int',
rule = 'cat ${SRC} > ${TGT}',
ext_in = '.txt', ext_out = '.int')
TaskGen.declare_chain(name = 'inttoh',
rule = 'cat ${SRC} > ${TGT}',
ext_in = '.int', ext_out = '.h')
bld.recurse(['prog', 'gen'])
In gen, all we need is to define build as bld(source = 'test.txt', target='test.h').
In prog, we build a program and only set the include path, don't mention test.h directly (main.c includes test.h):
def build(bld):
includes = [ bld.path.parent.find_dir('gen').get_bld().abspath() ]
bld.program(source = 'main.c', target = 'prog', includes = includes)
When I run waf at the top level, everything works as expected. When I run it from the prog directory though, it never triggers the creation of test.h. I was under the impression that the c preprocessor from scan shouldn't run until all nodes are created, but it seems if I run from the prog directory, waf doesn't know about these generated headers, even though they are defined as targets in the other directory's wscript file.
[edit: This makes some amount of sense I just realized - when running from top level it will schedule building the headers, and then dependencies will resolve fine. Waf does not seem to have a list of items that "could be built, if needed"]
There are some workarounds, such as using name and adding a use = ... directive in the C file wscript. Is there a way. though, to make it work automatically? It seems waf should have all the information it needs to make it work automatically.
(tested with waf 1.7.8 and 2.0.8)
When you launch waf in a subdirectory, it only posts the task generator defined in the subtree. This is to allow partial builds. waf know of your dependencies scanning includes in your C files, but as includes can be system includes, that does not trigger anything. To trigger a task generator in another part of your tree, the best thing to do is use =, in my opinion that's the best way. You can also go for using:
bld.program(source = ["main.c", "../gen/test.h"], ...)
but I find it less modular.

Building nested Autotools Package without Installing

What I want is to build my autotools package together with a nested autotools package. It's a static library and usually this package install the lib in your $prefix/lib folder, if you type make && make install
Sub-Package-Files:
configure.ac
AC_INIT([testlib],[1.0],[bugs#anonym.net])
AM_INIT_AUTOMAKE([foreign -Wall -Werror])
AC_PROG_CC()
AC_PROG_RANLIB()
AC_CHECK_HEADERS()
AC_LANG([C])
AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT
Makefile.am
SUBDIRS = src
src/Makefile.am
lib_LIBRARIES = libtestlib.a
libtestlib_a_SOURCES = testlib.c
include_HEADERS = testlib.h
But I want to use it as a nested package in my autotools package and need it only for linking while build time.
So how do I achieve that my package is build & installed but the sub- / nested package is only build without modifying the configure.ac or the Makefile.am from the sub-package?
So how do I achieve that my package is build & installed but the sub-
/ nested package is only build without modifying the configure.ac or
the Makefile.am from the sub-package?
Your best bet is probably to use AC_CONFIG_SUBDIRS in the top-level configure.ac to link configuration of the subpackage with the top-level package, but to avoid using SUBDIRS in the top-level Makefile.am to trigger make recursing into the subpackage. Instead of the latter, add a manual rule to the top-level Makefile.am for building the wanted library via a recursive make.
In the top-level package, that would look something like this:
configure.ac
# ...
AC_CONFIG_SUBDIRS([testlib-1.0])
# ...
Makefile.am
# ... testlib-1.0 *not* present in SUBDIRS ...
testlib-1.0/src/libtestlib.a:
$(MAKE) -C testlib-1.0
Be sure, then, to express a proper dependency on testlib-1.0/src/libtestlib.a where needed, and to use appropriate link options at the top level.
Use AC_CONFIG_SUBDIRS([testlib]). For code samples, read more about it in the documentation.
EDIT
If you wanted to build convenience libraries without touching the subpackage (for instance, if you stored it as a Git submodule in your main Git repository) then you could:
copy the relevant checks from the subpackage's configure.ac into your package's configure.ac
have your package's configure.ac include AC_OUTPUT([subpackage/Makefile])
leave subpackage out of SUBDIRS in Makefile.am
have your package's Makefile.am build the relevant parts of subpackage the way you want them, e.g.
noinst_LIBRARIES = subpackage/libsubpackage.a
subpackage_libsubpackage_a_SOURCES = subpackage/source.c etc.
This may not be what you want, as it involves duplicating a lot of subpackage's build system, but it does allow you to drop the subpackage into your package unchanged.
I'm not sure if this is too hackish, but giving the SUBDIRS variable a target-specific value seems to work and looks relatively elegant:
SUBDIRS = src
install installdirs: SUBDIRS =
or, more generally
SUBDIRS := foo bar libgazonk
install installdirs: SUBDIRS := $(filter-out libgazonk, $(SUBDIRS))
(Simple expansion necessary to avoid infinite recursion.)

How to make OCamlbuild compile and link a C file into an OCaml project?

I'm trying to build an OCaml binary main.native from main.ml that also relies on a single C file custom.c to implement a new primitive. This C file needs to be compiled and linked. Is there a way to do this just with a _tags file? The obvious problem is that OCamlbuild does not detect the dependency when scanning main.ml and hence needs to be told explicitly about the dependency.
ocamlbuild main.native
OCamlbuild knows a rule to compile a *.c file to a *.o file but I don't know how to add the dependency.
There are a number of resources out there.
The first thing is that you need to tag the main.native as to create a dependency on the c-stubs and link accordingly. (By the way, this assumes the c-library is called cstub, but it can be anything you'd like).
_tags :
<*.{byte,native}> : use_cstub
<**/*.cm{x,}a> : use_cstub
Then, in myocamlbuild.ml create a dependency of a c-library to the things tagged,
dep ["link";"ocaml";"use_cstub"] ["libcstub.a"]
OCamlbuild has rules for creating library files (*.so and *.a), but you would need to add a listing of the files to be built against in a .clib file,
cstub.clib :
cobjfile1.o
cobjfile2.o
...
Any header files also need to be copied over from the main directory to the _build/ directory. This is done by specifying they are a dependency on compilation in c (in myocamlbuild.ml, where headers is a list of strings naming the header files in the project.
dep ["c"; "compile"] headers;
and finally, adding flags to when we link the project with the c-stub library (also in myocamlbuild.ml),
flag ["link";"ocaml";"use_cstub"] (S[A"-dllib";A"-lcstub";A"-cclib";A"-lcstub"]);
I have accepted the answer above but would like to document the solution. As mentioned in a comment, I have created a new parametrized tag linkdep() using myocamlbuild.ml:
open Ocamlbuild_plugin;;
dispatch
( function
| After_rules -> pdep ["link"] "linkdep" (fun param -> [param])
| _ -> ()
)
The newly created tag is used in _tags to add a link dependency:
<*.ml>: annot
<*.byte>: linkdep(custom_unix_stubs.o),custom
<*.native>: linkdep(custom_unix_stubs.o)
This relies on built-in rules to compile a C file to an object file. However, this would still miss dependencies on header files (which I don't have).

How to use autotools for deep projects?

I have a C project that has the following structure
Main/
Makefile.am
bin/
src/
Makefile.am
main.c
SomeLibrarySource/
SomeFuncs.c
SomeFuncs.h
The main.c contains the main function that uses functions defined in the SomeFuncs.{h/c} files.
I want to use autotools for this project. I read a couple of resources on autotools. But, I was only able to manage using autotools for a single level project where all source, object and other files reside in the same directory.
Then I got some links that talked about using autotools for deep projects like this one and then I got confused.
Right now I have two Makefile.am as follows
Makefile.am
SUBDIRS=src
src/Makefile.am
mainprgdir=../
mainprg_PROGRAMS=main
main_SOURCES=main.c
I am pretty sure that these files should not be as I have them now :P
How do I use autotools for the above project structure? (At least what should be there in those Makefile.am(s) and where should I place them.
EDIT:
One more thing! At the end I would like to have the object files created in the bin directory.
Thanks
mainprogdir=../ does not make a whole lot of sense (you don't know what it is relative to on installation). Probably intended:
# Main/Makefile.am
# .━━ target for `make install`
# |
# ↓ ↓━━ target for compilation
bin_PROGRAMS = bin/main
# ↓━━ based upon compilation target name
bin_main_SOURCES = src/main.c
There are two main approaches. If the functions in SomeLibrarySource are used only by main, then there's no need to build a separate library and you can simply specify the source files in src/Makefile.am
main_SOURCES = main.c SomeLibrarySource/SomeFuncs.c
However, if you actually want to use the functions in other code in your tree, you do not want to compile SomeFuncs.c multiple times but should use a convenience library.
# Assigning main_SOURCES is redundant
main_SOURCES = main.c
main_LDADD = SomeLibrarySource/libSomeFuncs.a
noinst_LIBRARIES = SomeLibrarySource/libSomeFuncs.a
AM_CPPFLAGS = -I$(srcdir)/SomeLibrarySource
(You'll need AC_PROG_RANLIB in configure.ac to use convenience libraries.)
If the source file is named SomeFuncs.c, automake will not need Makefile.am to specify SomeLibrarySource_libSomeFuncs_a_SOURCES, but if the name of the source code file does not match the name specified in noinst_LIBRARIES, SomeLibrarySource_libSomeFuncs_a_SOURCES should be set to the list of files used to build the library. Note that you do not need to specify main_SOURCES, since main.c is the default value if left unspecified (but it's not a bad idea to be explicit.) (In all of this, I am not comfortable use CamlCase names, but the system I'm using uses a case insensitive file system (biggest mistake apple ever made) and the examples I give here are working for me. YMMV)
You could of course do a recursive make, or build the library as a separate project and install it. (I like the final option. Libraries with useful features should exist on their own.)

Resources