Rust Reference Mods - module

I have a set of files in a workspace which I want to reference from another directory, but I cannot find the syntax I need to use.
The example is:
Primary
|_______ First
| |_____ src
| |______ Cool_thing.rs
|_______ Second
|_____ src
|______ main.rs
I want to reference a struct in Cool_things from main.rs
In Primary's Cargo.toml I put:
[workspace]
members= ["First","Second", "Third"]
[dependencies.Second]
First= { path = "First" }
In the Cargo.toml in the Second directory I have
[dependencies]
First = { path = "../First" }
I have been trying things in my main.rs like:
extern crate First;
use First::Cool_things::Cool_things;
No variation of use or mod seems to allow me to reference the struct or impl or functions in mod Cool_things.

The problem was it needed a "lib.rs" in the First src directory. Basically, the documentation for rust seems to be a bit remiss in telling people if you want to use local-dependancies then you have to have a lib.rs file which lists all the mods you are planning to access. So the creation of a lib.rs in the First src directory, and listing "Mod Cool_things" would allow the other package to reference the mod files in that directory.
The cargo.toml files: Inserted in the question above had the correct paths and dependancies, the issue was all around the lack of a lib.rs file.
So if you are planning a multiple binary program, you'll need to remember to have a lib.rs file whenever you're breaking up your code and then accessing modules from other parts of the workspace.

Related

Why can't I import module from different file in same directory? [duplicate]

This question already has answers here:
How can I include a module from another file from the same project?
(6 answers)
Closed 3 years ago.
My directory structure:
src
main.rs
image.rs
decoders.rs
When I try to import my decoders module in image.rs I get this:
error[E0583]: File not found for module `decoders`
decoders.rs:
pub mod Decoders {}
image.rs:
mod decoders
use decoders::Decoders
pub mod Image {}
Note: I am using a module that wraps the entire file on purpose that's I can put attributes on entire files. This is why it's not a duplicate of How to include module from another file from the same project?
The weird thing is, is that this syntax works perfectly fine when I try to import Image in main.rs:
mod image;
use image::Image;
What's happening is that when you try to import decoders::Decoders in image.rs, you need to go through the next level up, because using this:
mod decoders
use decoders::Decoders
Means that decoders will now be "owned" or under image, which means that the compiler will search in the image subdirectory for decoders.rs. So, to fix this, you can either change your file structure to this:
src/
main.rs
image.rs ** or image/mod.rs
image/
decoder.rs
Or, use this in main.rs:
mod decoders;
mod image;
and this in image.rs:
use super::decoders::Decoders;
//Or alternatively
use crate::decoders::Decoders;
Also, to fix your nested-mod problem, do the following in decoders.rs:
//Your code, no `mod Decoders`
and the following where you have your mod decoders statement:
#[your_attribs]
mod decoders;
The rust compiler resolves modules differently depending on where they're defined.
When you use the mod keyword to declare an external module from the crate entry point (typically main.rs or lib.rs) or from a module root (mod.rs), the compiler will search for files adjacent to the declaring file. This is why it works properly when using mod image.rs in your main.rs file.
In other cases, the compiler will search for files in the folder with the same name as the declaring file. In your case, this means that your mod decoders; line in image.rs results in the compiler searching for the module in the image subfolder - specifically checking image/decoders.rs and image/decoders/mod.rs.
To fix this, you can either move decoders.rs to image/decoders.rs if you want to keep decoders as a submodule of image, or alternatively place mod decoders; in main.rs and leave the file where it is.

In Rust, what is the purpose of a mod.rs file?

In some Rust projects I've seen (i.e pczarn/rustboot), I've seen mod.rs files in directories for whatever reason. I've not been able to find documentation about this, and I've seen it in many other Rust projects.
What is the purpose of a mod.rs file, and when should I use it?
Imagine the following directory structure:
code/
`- main.rs
- something/
`- mod.rs
If in main.rs you do mod something;, then it'll look in the something/mod.rs file to use as the contents of the module declaration for something.
The alternative to this is to have a something.rs file in the code/ directory.
So to recap, when you write an empty module declaration such as mod something;, it looks either in:
a file called something.rs in the same directory
a file called mod.rs in a folder called something in the same directory
It then uses the contents of either of those files to use as the contents of the module declaration.
Modules are important to understand, but I find most documentations often leave you scratching your head on that matter.
Coming from Python or Javascript?
Roughly, mod.rs is kind of like __init__.py in python or index.js in javascript.
But only kind of. This is a bit more complicated in Rust.
Rust is different
Folders are not immediately ready to use as modules in Rust.
You have to add a file named mod.rs in a folder to expose a new module named like that folder.
The code in mod.rs is the content of that module.
All other files in the folder may in turn be exposed as submodules (more on that below).
Wait, there is another way
You may also use a file at the same level as a folder and named after that folder (<folder_name>.rs).
This is the preferred way since rustc 1.30. (Credits to MarkusToman in the comments)
From the Rust reference:
Note: Previous to rustc 1.30, using mod.rs files was the way to load
a module with nested children. It is encouraged to use the new
naming convention as it is more consistent, and avoids having many
files named mod.rs within a project.
Complete example
src
utils
bar.rs
foo.rs
main.rs
At this point, the compiler doesn't know about src/utils/foo.rs and src/utils/bar.rs.
First, you must expose src/utils/. As seen above, you have 2 options:
add the file: src/utils/mod.rs
add the file src/utils.rs (named exactly like the folder, without the extension)
Now, relative to the src folder (aka the crate level), a module named utils is available.
Second, you must expose the files src/utils/foo.rs and src/utils/bar.rs.
To do that, the utils module must declare 2 new submodules named after these files.
So the content of src/utils/mod.rs (or src/utils.rs) should be:
pub mod bar;
pub mod foo;
Now whatever is public in those 2 files is available in other modules! 🎉
And you may write the following in src/main.rs:
mod utils;
use utils::{foo, bar};
Resulting file structure
Option 1 • mod.rs (the old way):
src
utils
bar.rs
foo.rs
mod.rs
main.rs
Option 2 • <folder_name>.rs (the preferred way):
src
utils
bar.rs
foo.rs
utils.rs
main.rs
More advanced details on how modules work
This remains a surface explanation, your next destination is the official documentation 🧑‍🎓
There is a third way to declare modules (core language):
mod utils {
// module code goes here. That's right, inside of the file.
}
But it is also possible to just write mod utils;.
In that case, as seen above, Rust knows to search for either of src/utils.rs or src/utils/mod.rs.
See, when you try to use a module in a file (in src/main.rs for example),
you may reference it in the following ways:
from inside: src/main.rs
mod module { ... }
from nested modules inside: src/main.rs
mod module { pub mod sub_module { ... } }
from sybling files: src/*.rs
from mod.rs files in sybling folders: src/*/mod.rs
(and infinite reccursive combinations of the above)
A file or a folder containing mod.rs does not become a module.
Rather, the Rust language lets you organize modules (a language feature) with a file hierarchy.
What makes it really interesting is that you are free to mix all approaches together.
For example, you may think you can't directly reference src/utils/foo.rs from main.rs.
But you can:
// src/main.rs
mod utils {
pub mod foo;
}
Important notes:
modules declared in files will always take precedence (because you in fact never need to search the file hierarchy)
you can't use the other 2 approaches to reference the same module
For example, having both src/utils.rs and src/utils/mod.rs will raise the following error at compile time:
error[E0761]: file for module `utils` found at both "src/utils.rs" and "src/utils/mod.rs"
--> src/main.rs:1:1
|
1 | mod utils;
| ^^^^^^^^^^
|
= help: delete or rename one of them to remove the ambiguity
Let's wrap up. Modules are exposed to the compiler:
from top to bottom
by reference only
(That's why you don't have intellisense until your modules are "imported")
starting from an entry point
(which is src/main.rs or src/lib.rs by default.
But it may be anything that you configure in Cargo.toml.
This has little to do with this question however)
With our previous example we get in order:
src/main.rs -> crate
Because the crate module contains mod utils; we next get:
src/utils.rs OR src/utils/mod.rs -> crate::utils
Because the utils module contains mod foo; we next get:
src/utils/foo.rs -> crate::utils::foo
Each rs file, except lib.rs and main.rs, which always match the crate module, gets its own module.
There is only one way to declare a module:
/* pub */ mod sub_module1;
A module cannot be declare outside the root/crate module tree (i.e., going up the module tree, a submodule must always have a parent that is declared directly in lib.rs or main.rs, so the first program submodule must always be declared there — a tree data structure if it isn't already obvious enough).
There are 2 ways to nest a module inside the module where it is declared:
in <module_where_it_is_declared>/<module_name.rs>
in <module_where_it_is_declared>/module_name/mod.rs
If module_where_it_is_declared is the crate module, then this corresponding subfolder is not needed (disappears from the scheme above).
Here is an example, valid for both lib and binary crates:
src
|---lib.rs ( contains: pub mod b2; )
|---b2.rs ( contains: pub mod bb2; )
|---b2
| |---bb2.rs
. .
Alternatively:
src
|---lib.rs ( contains: pub mod b2; )
|---b2
| |---mod.rs ( contains: pub mod bb2; )
| |---bb2.rs
. .
You can see that you can mix and match (b2 uses mod.rs way, bb2 uses the "file"-way).
Here's a way to only use the file pattern that is also valid:
src
|---lib.rs ( contains: pub mod b2; )
|---b2.rs ( contains: pub mod bb2; )
|---b2
| |---bb2.rs (contains: pub mod bbb2; )
| |---bbb2.rs (contains: pub mod bbbb2; )
| |---bbb2
| | |---bbbb2.rs
. . .
I guess it depends on you how you want to nest modules.
I like the mod.rs syntax for modules that just export other submodules and don't have any other (or very little) code in them, although you can put whatever you want in mod.rs.
I use mod.rs similar to the barrel pattern from JS/TS world, to rollup several submodules into a single parent module.
Also don't forget modules can be defined (not only declared) inline by adding a scope block:
pub mod my_submodule {
// ...
}

How to organize Lua module path and write "require" calls without losing flexibility?

Say I have a project, whose folder structure looks like below:
| main.lua
|
|---<model> // this is a folder
| |a.lua
| |b.lua
|
|---<view>
|a.lua
|b.lua
model/a.lua requries model/b.lua: require "b"
view/a.lua requries view/b.lua: require "b"
main.lua requries files in model and view.
Now I have problem to get these modules loaded correctly. I know I can fix it by changing the require calls to:
model/a.lua: require "model.b"
view/a.lua: require "view.b"
But if I do that, I have to modify these files every time when I change the folder structure.
So my questions are:
How to fix the module path issue without hard code paths in module files?
Why Lua doesn't use the module search rule of Node.js, which looks easier?
When you require a module, the string parameter from require gets passed into the module which you can access using the variable-argument syntax .... You can use this to include other dependent modules which reside in the same path as the current module being requireed without making it dependent on a fixed hard-coded module name.
For your example, instead of doing:
-- model/a.lua
require "model.b"
and
-- view/a.lua
require "view.b"
You can do:
-- model/a.lua
local thispath = select('1', ...):match(".+%.") or ""
require(thispath.."b")
and
-- view/a.lua
local thispath = select('1', ...):match(".+%.") or ""
require(thispath.."b")
Now if you change directory structure, eg. move view to something like control/subcontrol/foobar, then control/subcontrol/foobar/a.lua (formerly view/a.lua) will now try to require control/subcontrol/foobar/b.lua instead and "do the right thing".
Of course main.lua will still need to fully qualify the paths since you need some way to disambiguate between model/a.lua and view/a.lua.
How to fix the module path issue without hard code paths in module files?
I don't have any better cross-platform solution, maybe you should plan the folder structure early on.
Why Lua doesn't use the module search rule of Node.js, which looks easier?
Because Lua tries its best to rely only on ANSI C, which is really successful. And in ANSI C, there's no such concept of directories.
There are a couple approaches you can use.
You can add relative paths to package.path as in this SO answer. In your case you'd want to add paths in main.lua that correspond to the various ways you might access the files. This keeps all the changes required when changing your directory structure local to one file.
You can add absolute paths to package.pathusing debug.getinfo -- this may be a little easier since you don't need to account for all the relative accesses, but you still need to do this in main.lua when changing your directory structure, and you need to do string manipulation on the value returned by debug.getinfo to strip the module name and add the subdirectory names.
> lunit = require "lunit"
> info = debug.getinfo(lunit.run, "S")
> =info.source
#/usr/local/share/lua/5.2/lunit.lua
> =info.short_src
/usr/local/share/lua/5.2/lunit.lua
The solution is to add the folder of main.lua (project root) to package.path in main.lua.
A naive way to support folders of 1 level deep:
-- main.lua
package.path = package.path .. ";../?.lua"
Note for requires in (project root) will look up files outside of project root, which is not desirable.
A better way of to use some library (e.g.: paths, penlight) to resolve the absolute path and add it instead:
-- main.lua
local projectRoot = lib.abspath(".")
package.path = package.path .. ";" .. projectRoot .. "/?.lua"
Then in you source use the folder name to scope the files:
-- model/a.lua
require "model.b"
-- you can even do this
require "view.b"
and
-- view/a.lua
require "view.b"

CMake: collecting libraries

I am using CMake to build a simple C++ project, hereafter named P. The structure of P is quite simple:
P/src/
P/src/package1
P/src/packege2
P/src/...
P/src/main-app
I would like to collect the libraries in package1, package2, ... in a variable called P_LIBS.
In a first attempt, I tried to collect the libraries available in package1, package2, ... in the variable called P_LIBS initially set in the src/CMakeLists.txt file. However, the updates to P_LIBS made in the CMakeLists.txt of the subfolders are not propagated to the parent folder.
I would rather not write a list of libraries in the main CMakeLists.txt file. I would rather modify such variable while moving in the directory tree.
After a search on the internet I could not find any valid suggestion. If I look at the various Find files, I only see long listings of libraries in their main CMakeLists.txt file.
Is there a way to do what (I hope) I explained above?
Thanks to sakra's link I was able to 'propagate' names up to the parent folder. However, the names I add to the P_LIBS variable are later interpreted as 'library' names, not as reference to CMake targets. In other words, if
P_LIBS = {a, b}
the 'a' and 'b' are interpreted as the library names, i.e. CMake generates:
gcc [...] -l a -o exe
instead of
gcc [...] /path/to/a.o -o exe
(.o or other extensions)
You are propably constructing the targets list as a string, try to make them a list instead. For example:
# in package1/CMakeLists.txt
set(P_LIBS ${P_LIBS} a b PARENT_SCOPE)

CMake: export third party headers to directory

Using CMake I am using a third party library, TinyThread++, it is a simple Thread library wrapper and only contains 1 source files and 2 header files.
In my project CMakeList.txt I added the following line:
add_library(TinyThread STATIC ${CMAKE_CURRENT_SOURCE_DIR}/../../third_party/TinyThread/source/tinythread.cpp)
And then added a dependency to this library to the my executable this is working great.
I am trying to figure out how to copy or export the two header files to a common include directory I am using in my project.
${CMAKE_CURRENT_SOURCE_DIR}/../../include
What is the recommended way to do this?
If you simply want to "use" those headerfiles while compiling, you can use include_directories() like Naszta explains.
In case you really want to copy the files, you can use configure_file() or file( COPY ... ) (check the bottom of the section on the file() command).
I think you should do something like this:
SET(TINY_THREAD_INCLUDE_PATH "${CMAKE_CURRENT_SOURCE_DIR}" CACHE PATH "TinyThread include path")
SET(TINY_THREAD_SOURCE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/tinythread.cpp" CACHE FILEPATH "TinyThread source file")
...
INCLUDE_DIRECTORIES(${TINY_THREAD_INCLUDE_PATH})
ADD_LIBRARY(TinyThread STATIC ${TINY_THREAD_SOURCE_FILE})
This way you could reuse them later by their name. If you would like to hide them in normal mode:
MARK_AS_ADVANCED(TINY_THREAD_INCLUDE_PATH TINY_THREAD_SOURCE_FILE)