I'm building a library and I have the following structure:
src/lib.rs
mod a;
mod b;
src/b.rs:
macro_rules! x ...
src/a.rs:
x!()
this doesn't work. I tried to fiddle with #macro_export and #macro_use but without success. What's the correct approach to re-using macros in the same library but in different module and file?
In order for macros from submodules to be visible to "sibling" modules they have to be declared in a certain order, that is, the module with macros should be declared the first. It also should have #[macro_use] attribute attached. This should work:
#[macro_use] mod b;
mod a;
#[macro_use] attribute makes macros from the module visible to all code "below" the module declaration, that's why your original variant could not possibly work.
Related
I have a module which holds global variables. To declare some global variables, I need to use HDF5. I am also using a library, so I also need to include a header file. So the preamble of global_variable.F90 looks like this.
module global_variables
use HDF5
#include "finclude/petscsys.h"
#include "finclude/petscvec.h"
integer(HID_T) id_file
integer(HID_T) id_plist
Vec M, C, K
...
end module
Vec is a data type defined in the header file and HID_T is a data type defined in HDF5 module.
Now, I have a file which holds subroutines for I/O. This file also uses HDF5 and the same library used in global_variables.F90. So IO.F90 looks like this.
module io
use global_varibles
contains
subroutine read_input_file( vector )
Vec vector
integer HDF5err
call H5open_f( HDF5err )
...
end subroutine
end module
Question 1: compiler returns error when compiling IO.F90, saying that Vec is undefined data type. But it does not complain about HID_T. I thought global_variables module already contains both HDF5 modules and header files, using global_variables module in IO.F90 will handle every data type declaration but it seems not. Could you please help me understand what I am understanding wrong?
Question 2: Is there a way to restrict the effect of #include to the module where it is declared?
PS. If I include #include "finclude/petscvec.h" in IO.F90, which declares Vec, then it compiles well.
The syntax
Vec vector
is completely alien to Fortran. It works only because Vec is a C pre-processor (CPP) macro defined in the header file "finclude/petscvec.h" as
#define Vec PetscFortranAddr
That means that you must include the header file in every Fortran file in which you use the above syntax with Vec. The macro cannot be inherited using the Fortran use because it is not a part of Fortran.
The PetscFortranAddr is in the end defined in "finclude/petscdef.h" as an integer with 4 or 8 bytes depending on your system.
There is probably nothing you can do except reverse engineering what it in the end the pre-processor makes to be, but I wouldn't go that way, it may be unportable.
I'm unable to import and use a module I've written, not sure where I went wrong.
My starting directory structure is:
/src/main.rs <- contains fn main()
/Cargo.toml
I wanted to refactor some code out of one big main file I had, so I ran
cargo new mnemonic
leaving me with:
/src/main.rs <- contains fn main()
/Cargo.toml
/mnemonic/src/lib.rs
/mnemonic/Cargo.toml
in the /mnemonic/src/lib.rs that was created I put:
pub mod mnemonic;
then put my code in /mnemonic/src/mnemonic.rs (has 2 public functions I want to use from main). I ran cargo build from mnemonic/ and back in my main src, I tried
extern crate mnemonic;
and
use mnemonic;
I also tried use mnemonic::mnemonic;
In all instances, it was unable to find the crate or gave an unresolved import error.
I've also tried putting my code containing the 2 pub functions in /src/mnemonic.rs
and in /src/main.rs putting:
use mnemonic;
I also tried just putting my code in mnemonic/src/lib.rs and trying extern crate mnemonic; use mnemonic; from src/main.rs
Am I supposed to edit Cargo.toml in any of the instances you proposed?
Updated Answer
Yes, you need to tell Cargo where to find your crate. In your binaries Cargo.toml, add something like:
[dependencies.mnemonic]
path = "./mnemonic"
Original Answer
When you create a new crate, it automatically has one layer of namespacing: the name of the crate itself. In addition, you don't need to extern use a crate if it is your current crate!
Using crate mnemonic from other crates
This is probably what you want to do: Create a new crate called mnemonic, then you will have a src/lib.rs. Put your code in there, and you can then use it from other crates with
extern crate mnemonic;
use mnemonic::ItemInLibDotRs; // Make sure this item is marked as `pub`!
Using a nested module mnemonic from the crate mnemonic
Say you have some implementation detail you want to hide from the end user. We will put it in a module within the crate, and use it only from within the same crate.
Put your code in src/mnemonic.rs. In src/lib.rs, you will reference that module and items:
use mnemonic::ItemInMnemonic; // Make sure this is `pub`!
mod mnemonic;
Using a nested module mnemonic from the crate mnemonic in other crates
Export the module from your crate, and then reference it from other crates:
// src/lib.rs
pub mod mnemonic; // Note the module is now public
// In the crate that consumes mnemonic
extern crate mnemonic;
use mnemonic::mnemonic::ItemInMnemonic;
This last option is kind of ugly though, you probably don't want to make your users type mnemonic::mnemonic, which is why I suggest just putting it in src/lib.rs.
All examples that I found create a lib.rs and then inside that file create mod foo;, mod bar; for each file foo.rs, bar.rs and so on.
Basically what I want is to to split my crate into multiple files but without having to introduce lots of modules for every file. Is this not possible with Rust?
In order to include another source file, it has to be its own module.
However, this does not mean that you must expose this fact in your API. For example, let's say you want to put some code in a file called hidden.rs:
pub fn inside_hidden() {}
Now in your lib.rs file, you could expose this module:
#![crate_type = "lib"]
pub mod hidden;
But if your library doesn't require sub-modules, it's probably better to keep the hidden module a secret, and instead expose its contents as members of your top-level module:
#![crate_type = "lib"]
pub use hidden::inside_hidden;
mod hidden;
This way, users won't know you have a hidden sub-module. They will see inside_hidden as if it were a member of your top-level module.
i have a module 'gvars' defined for my global variable declarations. when i define
integer :: nthreads, max_threads, tid, omp_get_max_threads, omp_get_num_threads, omp_get_thread_num inside of my gvars module, the call maxthreads = omp_get_max_threads() in my main routine gives me the following error upon compilation:
maxthreads = omp_get_max_threads()
1
Error: Unclassifiable statement at (1)
but when i include the integer :: definitions above inside my main routine, it compiles just fine and gives me the desired results. if i even go as far as to define nthreads = -1 inside my gvars module, i am able to print out the correct value in my main routine so i know it is being included and defined correctly, it's just that for some reason i cannot have it as a return value from openmp functions.
why would this be?
is there any other way to keep these values as global variables and still define them in my main routine instead of a module?
if it matters, i am using gfortran to compile
The problem is not with the declaration of maxthreads, but with the declaration, on the same line, of omp_get_max_threads. As haraldkl showed, you need to use omp_lib instead, to automatically get access to the declarations of these functions.
(If for some reason you really don't want to do it that way, you can also add the statement external :: omp_get_max_threads, ... to the module.)
Not really an answer, but I do not know how else to put the code in here. Sorry...
module gvars
integer :: maxthreads
end module gvars
program test
use gvars
use omp_lib
implicit none
maxthreads = omp_get_max_threads()
end program test
compiled with:
gfortran -fopenmp test.f90
Where gfotran -v gives:
gcc version 4.4.5 (GCC)
Suppose I have a module which defines some basic constants such as
integer, parameter :: i8 = selected_int_kind(8)
If I include this in my main program and I also include a module which does some other things (call this module functions) but functions also uses constants, then am I essentially including constants twice in my main program?
If so, is this bad? Can it be dangerous at all to include a module too many times in a program?
No, it is fine to do this. All you are doing with the use statement is providing access to the variables and functions defined in your module via use association. It is not like declaring variables each time they are use'd (they are in fact redeclared however).
The only thing to be wary of are circular dependencies, where module A uses module B and module B uses module A. This is not allowed.
Edit: From Metcalf et al. Fortran 95/2003 explained, pg. 72:
A module may contain use statements that access other modules. It must not access itself directly or indirectly through a chain of use statements, for example a accessing b and b accessing a.
Whilst this quote doesn't directly answer your question, it reiterates that really the only thing you can't do is have a circular dependency. So the following is perfectly valid:
module one_def
implicit none
integer, parameter :: one=1
end module one_def
module two_def
use one_def, only : one
implicit none
integer, parameter :: two=one+one
end module two_def
program test
use one_def, only : one
use two_def, only : two
implicit none
print*, two == one+one ! This prints .True.
end program