How to include files from same directory in a module using Cargo/Rust? - import

I have a Cargo project consisting of three files in the same directory: main.rs, mod1.rs and mod2.rs.
I want to import functions from mod2.rs to mod1.rs the same way I would import functions from mod1.rs to main.rs.
I've read about the file structure required but I don't get it - naming all the imported files mod will lead to minor confusion in the editor and also this just complicates the project hierarchy.
Is there a way to import/include files independently of directory structure as I would in Python or C++?
main.rs:
mod mod1; // Works
fn main() {
println!("Hello, world!");
mod1::mod1fn();
}
mod1.rs:
mod mod2; // Fails
pub fn mod1fn() {
println!("1");
mod2::mod2fn();
}
mod2.rs:
pub fn mod2fn() {
println!("2");
}
Building results in:
error: cannot declare a new module at this location
--> src\mod1.rs:1:5
|
1 | mod mod2;
| ^^^^
|
note: maybe move this module `src` to its own directory via `src/mod.rs`
--> src\mod1.rs:1:5
|
1 | mod mod2;
| ^^^^
note: ... or maybe `use` the module `mod2` instead of possibly redeclaring it
--> src\mod1.rs:1:5
|
1 | mod mod2;
| ^^^^
I can't use it as it doesn't exist as a module anywhere, and I don't want to modify the directory structure.

All of your top level module declarations should go in main.rs, like so:
mod mod1;
mod mod2;
fn main() {
println!("Hello, world!");
mod1::mod1fn();
}
You can then use crate::mod2 inside mod1:
use crate::mod2;
pub fn mod1fn() {
println!("1");
mod2::mod2fn();
}
I'd recommend reading the chapter on modules in the new version of the Rust book if you haven't already - they can be a little confusing for people who are new to the language.

Every file is a module and cannot import another without creating a new nested module.
a. Define modules in module index file
As #giuliano-oliveira's answer recommends.
Add pub mod mod1; pub mod mod2; in src/lib.rs / src/main.rs / src/foo/mod.rs.
b. Use #[path]
main.rs
#[path = "./mod2.rs"]
mod mod2;
fn run() { mod2::mod2fn() }
Why?
This is a common pitfall for new Rust devs and understandably so.
The reason for the confusion comes from an inconsistency in behavior of mod X for files in the same folder. You can use mod X in lib.rs which appears to import a file adjacent to it, but you can't do the same in mod1.rs or mod2.rs.
The code of every file belongs to a module. The full path of the file's module (e.g. foo::bar::baz) rather than the location of the file, determines how it resolves mod X. You can think of it as every module having a fixed spiritual home, but it may have members defined further up in the hierarchy (e.g. src/lib.rs might contain: mod foo { mod bar { pub fn hello() {} } } - although then you cannot use mod foo; alone in lib.rs).
In main.rs, you are in the top-level module crate.
mod mod1; creates a new module mod1, and adds the contents of ./mod1.ts to that module.
So all code inside ./mod1.rs is inside the crate::mod1 module.
When you call use mod2 inside ./mod1.rs, it sees that it is inside crate::mod1, whose spiritual home dir is src/mod1, and looks for either:
src/mod1/mod2.rs
src/mod1/mod2/mod.rs
The complexity comes from allowing modules to be directories and also files, instead of forcing each module to be its own directory (maybe trying to avoid the Java folder structure) which would have removed the ambiguity.
The key thing to remember is that lib.rs and mod.rs are special files that behave differently to other files in a directory.
They will always be in the module described by the parent folder path (e.g. src/foo/bar/mod.rs = foo::bar) while all other files belong to their own modules (src/foo/bar/baz.rs = foo::bar::baz).
The Rustonic Way
Rust has some opinions on this.
Using mod.rs is not recommended anymore, which is good because it has this special behavior from its siblings. But lib.rs and main.rs are still special.
If you want to put tests alongside your code (foo.rs + foo_test.rs), it's recommended you don't. I don't like this, so I use the path thing above, which I think is fine for tests because they are not exported anywhere. Having to declare tests in the module above feels wrong, and I don't like having to use foo/test.rs either.

If you don't want your mod statements all in your main file (eg: in main.rs you won't use some public members inside some module, in this example it is mod2) you can do the following:
structure your src this way:
main.rs
my_module:
mod.rs
mod1.rs
mod2.rs
then you can just mod my_module and use my_module::mod1, like so:
main.rs:
mod my_module;
use my_module::mod1;
fn main() {
println!("Hello, world!");
mod1::mod1fn();
}
my_module/mod.rs
pub mod mod1;
pub mod mod2;
my_module/mod1.rs
use super::mod2;
pub fn mod1fn() {
println!("1");
mod2::mod2fn();
}

Related

Rust: no `module` in the root

When I run use crate::feed; in src/cmdline.rs I expect that to import src/feed.rs, but it doesn't. Instead I get,
error[E0432]: unresolved import `crate::feed`
--> src/cmdline.rs:2:5
|
2 | use crate::feed;
| ^^^^^^^^^^^ no `feed` in the root
Despite the fact that src/feed.rs exists. However, if I panic and change it to mod feed; then I get
error[E0583]: file not found for module `feed`
--> src/cmdline.rs:2:1
|
2 | mod feed;
| ^^^^^^^^^
|
= help: to create the module `feed`, create file "src/cmdline/feed.rs"
Using mod super::
error: expected identifier, found keyword `super`
--> src/cmdline.rs:2:5
|
2 | mod super::feed;
| ^^^^^ expected identifier, found keyword
Or with use super::
error[E0432]: unresolved import `super::feed`
--> src/cmdline.rs:2:5
|
2 | use super::feed;
| ^^^^^^^^^^^ no `feed` in the root
File structure for files in question looks like this,
src/feed.rs
src/cmdline.rs
src/main.rs
I figured it out. The rust module system doesn't permit importing sibling files,
src/a.rs
src/b.rs
Full stop: a.rs can not import b.rs. What it will do is try to source it from
src/a/b.rs
If you're on this answer, none of this probably makes sense to you and you've wasted hours on this. This was a source of my confusion:
src/main.rs
Is actually special. Inside src/main.rs a mod will import a sibling file, (and also with the now deprecated mod.rs; or, with lib.rs). But the point is that your own rust files can't make use of rust code in sibling files.
I was able to make my imports work the way you describe by doing the following.
First in main.rs I import the module cmdline and each module I want to be able to use via crate::.
// file src/main.rs
mod cmdline;
mod feed; // <== import module to be able to use via `crate::feed`
fn main() {
cmdline::do_something();
}
Then in cmdline.rs I use create::feed.
// file src/cmdline.rs
use crate::feed; // <== import sibling module
pub fn do_something() {
feed::do_something_else();
}
And my feed.rs looks something like this.
// file src/feed.rs
pub fn d_something_else() {
// ...
}
From what I understand from experimenting is that you need to first use mod in your main.rs to define which modules are included in your crate.

How to import other source code files in dm script

Is there a way to use multiple code files in dm-script to structure the code? Something like:
import "path/to/utility_functions.s";
utility_functions.do_something_general();
Note that I do not want to have the code as a menu item if possible. The code contains only functions that I use in the main script.
I tried the following:
File 1: test.s
void test(){
result("test\n");
}
File 2: require-test.s
AddScriptFileToPackage("path/to/test.s", "test", 3, "test-function", "", "", 1);
ExecuteScriptString("test()"); // works immediately but feels wrong
test(); // works after restart
Now I have the following problems:
I have to restart DigitalMicrograph after executing this script, otherwise test() does not work (ExecuteScriptString("test()"); works but it feels wrong to use strings for invoking code, if possible I'd like to avoid that)
When I restart DigitalMicrograph another time AddScriptFileToPackage() sais 'The script cannot be added because the package exists and is read-only. [...]'. Is there a way around it or do I have to use try blocks?
I feel like I am not doing this wrong at some place.
DM script does not support on-demand-loading of packages, but there are two different ways to achieve what you want:
Using library packages
When you "install" a script, you can choose to either install it as menu-command or as a library. This is true for both installing scripts via the menu command (which get stored in the global preferences file) or via the scripting-command (which can be used to
create .gtk files which one can then add/remove from the plugins
folder as needed).
The "menu" option will install a script such that it is invoked once via the menu-item but does not stay in memory otherwise.
The "library" option will execute a script once on startup and keep the script itself in scope. So you can define methods (or classes) in a library file and have it generally available. And you can put some executable code in a library if you need some startup-action.
Using script libraries as .gtk plugins is possibly the recommended way to achieve what you want. They are, however, always loaded.
Piece of advise: If you make libraries ensure you use very unique class and method names to avoid any conflict. I would recommend pre-fixing all class/method names with some library-name, i.e. use MyLib_MyClass instead of MyClass and the like.
Clarification: Scripts added as library packages are permanently added to the software, i.e. those packages get created once and are then placed in the plugins-folder. They will always load on startup of DM and be available. The Library package method is not suitable for temporarily 'loading' external scripts. Such 'on demand import' is not supported by DM-scripting.
The script commands to create packages are utility commands to help one create packages in an easy and manageable way. Typically, one would create a "Create package XY" script with several such commands adding all scripts from a location into a package. The script would be called once to create the package-file (It is already in the plugins folder afterwards.)
Only when the included scripts change and the package therefore requires to be updated, is the create-package script called again. Note, that in this case it is first required to remove the package-file from the plugins folder and start DigitalMicrograph without loading it, so that a new package is created. Otherwise the script would append to the package, which would not be possible if methods of the same name already exist in the package.
The F1 help documentation has an example script:
A typical examples, using GMS 3.4.0:
Script stored at: C:\Tmp\testLib.s
void TestCall()
{
Result("\nTest")
}
Script stored at: C:\Tmp\menuAction.s
Result("\nPerforming an action here.")
One-time run script to install a package:
// General package parameters
// *********************************************
string pkNa = "myPkg" // Filename of plugin
number pkLe = 3 // level 3 (.gtk) only needed for load order
string pkLo = "user_plugin" // plugin location
string scriptRoot = "C:\\Temp\\"
// List of Scripts to be installed as menu items
// *********************************************
// Each entry needs a (unique) command-name, a menu-name and an optional sub-menu name.
// The "isLibary" flag is set to 0
// It is possible to add the same script multiple times. The script will be executed when the menu item
// is chosen. Methods and Classes of the script are not available otherwise
// A separator can be added by installing and empty script with a (unique) command name starting with "-"
AddScriptFileToPackage( scriptRoot + "menuAction.s", pkNa, pkLe, pkLo, "Call 1", "MyMenu", "MySubMenu", 0 )
AddScriptFileToPackage( scriptRoot + "menuAction.s", pkNa, pkLe, pkLo, "Call 2", "MyMenu", "", 0 )
AddScriptToPackage( "", pkNa, pkLe, pkLo, "-sep1", "MyMenu", "", 0 )
AddScriptFileToPackage( scriptRoot + "menuAction.s", pkNa, pkLe, pkLo, "Call 3", "MyMenu", "", 0 )
// List of Scripts to be installed as library
// *********************************************
// Each entry needs a (unique) command-name. Menu-name and sub-menu name are "".
// The "isLibary" flag is set to 1
// The script will be executed once on startup (if there is executable code). It is also executed once
// here during the install.
// Methods and Classes of the script are permanently available and need unique names.
// Adding a script to the package as libary can be used to create on-load-version info output.
AddScriptFileToPackage( scriptRoot + "testLib.s", pkNa, pkLe, pkLo, "library-1", "", "", 1 )
AddScriptToPackage( "Result(\"Script packages myPkg loaded.\\n\")", pkNa, pkLe, pkLo, "myPkg-versionInfo", "", "", 1 )
After running the install-script there will be:
A menu like this:
Output in the results window like this:
A package file in the folder C:\Users\USERNAME\AppData\Local\Gatan\Plugins\myPkg.gtk
The script command TestCall() generally available in all scripts.
The package will load each time when DM starts as long as the .gtk file remains in the plugins folder.
Calling script code from within scripts
The scripting language supports two commands to call a script from within a script:
Number ExecuteScriptString( String text )
Number ExecuteScriptFile( String file_path )
Using the command to execute scripts form disc can do what you want, but maintaining a useful 'library' that way could be tedious. It also does not allow you to install classes.
Example of calling a script from within a script:
// Direct example
void Demo()
{
ClearResults()
Result( "I am a test call.\n")
number n = 5
Result( "I am working on the number: " + n )
}
Demo()
//Having the script as a string
number otherNumber = 11 // To show how you can modify a script call as an example
string scriptStr
scriptStr += "void Demo()\n{" + "\n"
scriptStr += "ClearResults()" + "\n"
scriptStr += "Result( \"I am a test call.\\n\")" + "\n"
scriptStr += "number n = " + otherNumber + "\n"
scriptStr += "Result( \"I am working on the number: \" + n )"+ "\n"
scriptStr += "}\n"
scriptStr += "Demo()\n"
If ( TwoButtonDialog("Script-call","Show it", "Run it") )
{
ClearResults()
Result( scriptStr )
}
else
ExecuteScriptString( scriptStr )
The following explicit example of build script usage may be closer to what you are looking for. It shows that in the course of a single DM session, one can edit the module source files and repeatedly rebuild the package without having to relaunch DM, contrary to the clarification about package creation provided in the answer from BmyGuest. This example also makes use of the very convenient GetCurrentScriptSourceFilePath function which greatly simplifies file path references when one can locate the build script and module source files in the same folder (this is the approach I take with my own development projects).
Here is the arrangement of my files for this example:
The two source modules are very simple function and class libraries.
Here is Module1:
void Module1SayHello()
{
OKDialog("Hello from module 1");
}
And here is Module2:
class Module2TestClass
{
void Module2SayHello(Object self)
{
OKDialog("Hello from module 2");
}
}
Here is the build script:
void main()
{
// Establish the source code directory relative to the current build script location
String buildScriptSourceFilePath;
GetCurrentScriptSourceFilePath(buildScriptSourceFilePath);
String sourceFileDir = buildScriptSourceFilePath.PathExtractDirectory(0);
// Add the modules
AddScriptFileToPackage(sourceFileDir.PathConcatenate("Module1.s"), "MultiModuleTest", 3, "Module1", "", "", 1);
AddScriptFileToPackage(sourceFileDir.PathConcatenate("Module2.s"), "MultiModuleTest", 3, "Module2", "", "", 1);
}
main();
Contrary to the above-mentioned clarification, this build script can be run multiple times during a DM session and the content of the package file gets replaced each time. So now one has a very nice development environment where one can open the source file for a module, edit it as desired, save it, and then rebuild the package file. One can use the following test script to see that the behavior changes as one edits, saves, and rebuilds the implementation of any function or method in the module source files:
void main()
{
Module1SayHello();
Alloc(Module2TestClass).Module2SayHello();
}
main();
Because of the way the DM script interpreter parses, tokenizes, and executes code, all functions and methods invoked anywhere in a script must have been previously defined before a script is executed. This is why the above test script, or any other script that uses the added modules, cannot simply be appended to the end of the build script (except if embedded in a string passed to the ExecuteScriptString function, as pointed out in the posed question). The concept of imported code modules (e.g. as in Python) is therefore not really possible in DM scripting (as pointed out in a comment to the answer by BmyGuest). In this sense, DM scripting shows its roots in 1990’s coding concepts, which commonly involved separate compilation, linking, and execution phases.
Nevertheless, the build script approach described here allows one to take advantage of the features of a true integrated development environment (IDE). For example, one can add the module source files (and build script) to a project in Visual Studio and get all the benefits of a modern multi-file code editor and revision control (e.g. via Git). This is what I do with the Enabler framework.
The one caveat is that once the DM session is closed, the plug-in (package) file does become finalized in some way so that it can no longer be replaced by the build script in a future DM session. In this case, one does have to remove the package file from the plug-ins folder before resuming another development session in DM (as covered in the clarification from BmyGuest).
For everybody else who needs this, I am using AddScriptFileToPackage() now, inspired by both, #BmyGuest and #MikeKundmann.
The following main.s is always open in my GMS. The real code I'm working on is in program.s. To test your code execute the main.s. This file can be executed multiple times in one session!
For opening GMS I use the (Windows) batch file below. This deleteds registered plugins automatically which makes the main.s usable again. For debugging I created a python script that combines all the files listed in the main.s. This way GMS jumps to the errors. This python program can be downloaded from my github page.
/**
* File: main.s
*/
String __file__;
GetCurrentScriptSourceFilePath(__file__);
String __base__ = __file__.PathExtractDirectory(0);
/**
* Load and add the file `filename`, the name will be the `filename` without
* the extension.
*
* This is dynamic only for the current session. If GMS is restarted, using
* this will create errors except if the plugins folder does not contain the
* required files (delete `%LOCALAPPDATA%\Gatan\Plugins\` before starting).
*
* #param filename The filename (or path) relative to the path of this file
* #param name The internal name to register the script with
*/
void require(String filename, String name){
// AddScriptFileToPackage(
// <file_path>,
// <packageName: filename of .gtk file in plugins>,
// <packageLevel: load order [0..3]>,
// <command_name: id/name of the libary/command>,
// <menu_name: name of the menu, ignored if isLibrary=1>
// <sub_menu_name: name of the submenu, ignored if isLibrary=1>,
// <isLibrary: wheter to add as library (1) or as menu item (0)>
// )
AddScriptFileToPackage(__base__.PathConcatenate(filename), "__require_main_" + name, 3, name, "", "", 1);
}
/**
* Require the file `filename` with the basename of the `filename` as the name.
*
* #see require(String filename, String name);
*
* #param filename The filename (or path) relative to the path of this file
*/
void require(String filename){
require(filename, PathExtractBaseName(filename, 0));
}
void main(){
// add libaries
require("string-lib.s");
// add main file
require("program.s");
}
main();
The (Windows) batch file to start GMS. This deletes the plugins folder automatically. Then the main.s does not cause any problems.
#echo off
rem
rem File: start-gatan.bat
rem ---------------------
echo Deleting GMS cached libaries...
SET plugins_path=%LOCALAPPDATA%\Gatan\Plugins\
SET gms_path=%PROGRAMFILES%\Gatan\DigitalMicrograph.exe
if exist %plugins_path% (
echo Deleting all .gtk files in %plugins_path%...
del %plugins_path%__require_main_*.gtk /F /Q
del %plugins_path%__require_main_*.gt1 /F /Q
del %plugins_path%__require_main_*.gt2 /F /Q
del %plugins_path%__require_main_*.gt3 /F /Q
if exist "%gms_path%" (
echo Starting GMS
start "" "%gms_path%"
) else (
echo GMS path %gms_path% does not exist.
pause
)
) else (
echo Plugins path %plugins_path% does not exist.
pause
)

Rust file not found for module error for file in same directory [duplicate]

This question already has answers here:
Including a file from another that is not main.rs nor lib.rs
(1 answer)
How do I import from a sibling module?
(1 answer)
How can I include a module from another file from the same project?
(6 answers)
How to use one module from another module in a Rust cargo project?
(3 answers)
Closed 3 years ago.
Rust cannot find local file through declaration. I have the following file structure in src:
| main.rs
| lib.rs
| test.rs
| prog.rs
| file.rs
In main.rs I have
extern crate cratename;
mod prog;
use cratename::file1::File1;
...
prog::function() // This works
...
#[cfg(test)]
mod test;
In lib.rs I have
pub mod file1;
In test.rs I have
extern crate cratename
use cratename::file1::File1;
mod prog;
#[test]
...
prog::function() // This does not work
...
I keep getting the error
error[E0583]: file not found for module `prog`
I tried putting the declaration in lib.rs but that didn't work. I've tried numerous other permutations involving this declaration along with main.rs but none of it worked. If it helps, prog.rs doesn't contain a struct and it doesn't use the mod keyword, it only contains public functions. This has stumped me for a while. Thank you for your help.

Postgres PL/JAVA: java.lang.ClassNotFoundException error after loading JAR file in database

I am getting the java.lang.ClassNotFoundException: error inside Postgres when running a function that calls a JAR file I have loaded. I have installed and configured PL/JAVA (including the delivered examples) in my database and can run the examples to success. I am not attempting to load/install my first JAR, but I am doing something wrong.
My host controls the OS version: CentOS 6.8. Postgres is version 8.4.
I am attempting to install my own very simple java class, which is a derivative of the delivered example Parameters.addOne class. All my code is in /tmp. Here are the steps I've followed:
Doug.java:
package com.msmetric;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.logging.Logger;
public class Doug {
public static int addOne(int value) {
return value + 1;
}
}
Compile Doug.java using 'javac Doug.java' succeeds.
Create JAR file with Doug.class file in it using 'jar -cvf Doug.jar Doug.class. This works fine.
Now I load the JAR file into Postgres (public schema), change the classpath, create the function that calls the JAR, then attempt to run at psql prompt.
Run sqlj.install_jar from psql:
select sqlj.install_jar('file:/tmp/Doug.jar','Doug',false);
Set the classpath inside Postgres (from psql prompt postgres=#):
select sqlj.set_classpath('public','Doug');
Create the function that calls the JAR. This create function code is taken directly from the examples.ddr file that came with PL/JAVA. I simply changed org.postgres to com.msmetric.
create or replace function addone(int) returns int as 'com.msmetric.Doug.addOne(java.lang.Integer)' language java;
Now with the JAR loaded and function created, I attempt to run it. This function should simply add 1 to the number provided.
select addone(3);
Results:
ERROR: java.lang.ClassNotFoundException: com.msmetric.Doug
Thoughts?
I'm very sorry I didn't see your question sooner. Underneath all the exotic details (PostgreSQL, PL/Java, schemas, classpaths...), there's just a bit of basic Java going on here: if a jar file contains a class Doug.class in package com.msmetric, its path within the jar has to reflect that: it has to be com/msmetric/Doug.class. Otherwise, it won't be found.
You can set up that whole structure step by step:
javac Doug.java
mkdir com
mkdir com/msmetric
mv Doug.class com/msmetric/
jar -cvf Doug.jar com/msmetric/Doug.class
Or, you can let javac do more of the work for you:
mkdir classes
javac -d classes Doug.java
jar -cvf Doug.jar -C classes .
When you give javac a -ddirectory option, instead of just writing class files next to their .java sources, it will put them all in their proper places under the directory you named, and then you can just tell jar to change into that directory and slurp them all up (don't overlook the . at the end of that jar command).
Once you fix that, if you retry your original steps, you'll see that you now get a different error:
ERROR: Unable to find static method com.msmetric.Doug.addOne with signature (Ljava/lang/Integer;)I
That happens because you declared the function in Doug.java with int addOne(int value) (that is, taking a primitive int argument), but you declared it in SQL with returns int as 'com.msmetric.Doug.addOne(java.lang.Integer)' taking an Integer object.
Once you correct that:
create or replace function addone(int) returns int as 'com.msmetric.Doug.addOne(int)' language java;
you'll be able to see:
# select addone(3);
addone
--------
4
(1 row)
If you happen to see this belated answer, may I ask what version of PL/Java you are using? That's one detail you didn't mention. If it is older than 1.5.0, there are newer features that can help you out. For one, you can just annotate that function:
#Function
public static int addOne(int value) {
return value + 1;
}
and have javac spit out not only the Doug.class file but also a pljava.ddr file with your SQL function declaration already written correctly (no mixing up argument types!). There is a way to include that .ddr file into the jar you create so that you can just call sqlj.install_jar with the last parameter true so it runs the commands in the .ddr and your functions are ready to use. There's a Hello, world example in the docs that shows more of how it's done.
Cheers,
-Chap

Protobufs import from another directory

While trying to compile a proto file named UserOptions.proto which has an import named Account.proto using the below command
protoc --proto_path=/home/project_new1/account --java_out=/home/project_new1/source /home/project_new1/settings/Useroptions.proto
I get the following error :
/home/project_new1/settings/UserOpti‌​ons.proto: File does not reside within any path specified using --proto_path (or -I). You must specify a --proto_path which encompasses this file.
PS: UserOptions.proto present in the directory /home/project_new1/settings
imports Account.proto present in the directory
/home/project_new1/account
Proto descriptor files:
UserOptions.proto
package settings;
import "Account.proto";
option java_outer_classname = "UserOptionsVOProto";
Account.proto
package account;
option java_outer_classname = "AccountVOProto";
message Object
{
optional string userId = 1;
optional string service = 2;
}
As the error message states, the file you pass on the command line needs to be in one of the --proto_paths. In your case, you have only specified one --proto_path of:
/home/project_new1/
But the file you're passing is:
/home/project_new1/settings/UserOpti‌ons.proto
Notice that the file is not in the account subdirectory; it's in settings instead.
You have two options:
(Not recommended) Pass a second --proto_path argument to add .../settings to the path.
(Recommended) Use the root of your source tree as the proto path. E.g.:
protoc --proto_path=/home/project_new1/ --java_out=/home/project_new1 /home/project_new1/settings/UserOpti‌ons.proto
In this case, to import Account.proto, you'll need to write:
import "acco‌​unt/Account.proto";
For those of us who want this really spelled out, here is an example where I have installed the protoc beta for gRPC using NuGet Packages Google.Protobuf, Grpc.Core and Grpc.Tools. My solution packages are one level above my Grpc directory (i.e. at BruTrader\packages). My .proto files are at BruTrader\Grpc\protos.
1. My .proto file:
syntax = "proto3";
import "timestamp.proto";
import "enums.proto";
package BruTrader.Grpc;
message DividendMessage {
double amount = 1;
google.protobuf.Timestamp dateUnix = 2;
}
2. my GenerateProto.bat file:
..\packages\Google.Protobuf.3.0.0-beta2\tools\protoc.exe -I..\Grpc\protos -I..\packages\Google.Protobuf.3.0.0-beta2\tools\google\protobuf --csharp_out=..\Grpc\Generated --grpc_out=..\Grpc\Generated --plugin=protoc-gen-grpc=..\packages\Grpc.Tools.0.13.0\tools\grpc_csharp_plugin.exe %1
3. my BuildProtos.bat
call GenerateProto ..\Grpc\protos\masterinstrument.proto
call GenerateProto .\protos\instrument.proto
etc.
4. BuildProtos.bat is executed as a Pre-build event on my Grpc project like this:
CD $(ProjectDir)
CALL "$(ProjectDir)BuildProtos.bat"
For my environment, Windows 10 Pro operating system and C++ programming languaje, I used the protoc-3.12.2-win64.zip that you can downloat it from here. You should open a Windows PowerShell inside the protoc-3.12.2-win64\bin path and then you must execute one of the next commands:
.\protoc.exe -I=C:\Users\UserName\Desktop\SRC --cpp_out=C:\Users\UserName\Desktop\DST C:\Users\UserName\Desktop\SRC\addressbook.proto
Or
.\protoc.exe --proto_path=C:\Users\UserName\Desktop\SRC --cpp_out=C:\Users\UserName\Desktop\DST C:\Users\UserName\Desktop\SRC\addressbook.proto
Note:
1- My source folder is in: C:\Users\UserName\Desktop\SRC
2- My destination folder is in: C:\Users\UserName\Desktop\DST
3- My .proto file is in: C:\Users\UserName\Desktop\SRC\addressbook.proto