How to handle file path when i am accessing file from other go file than main.
in other.go file i am trying to run ParseFS but it's giving the template: pattern matches no files: templates/test.tmpl error. Here is my file tree.
├── go.mod
├── main
│ └── main.go
└── other
├── other.go
└── templates
└── test.tmpl
other/other.go
package other
import (
"embed"
"fmt"
"html/template"
)
var templateFS embed.FS
func Check() error {
_, err := template.New("email").ParseFS(templateFS, "templates/"+ "test.tmpl")
if err != nil {
fmt.Println(err)
}
return nil
}
main/main.go
func main() {
err :=othher.Check()
if err != nil {
fmt.Println(err)
}
}
Go is a statically linked language. Whatever source you write, in the end the go tool will compile it into an executable binary. The source files will not be required afterwards to run the binary.
The embed package gives you a mean to include static files in the executable binary which you can access at runtime (the original, included files don't need to be present when you run the app).
However, the go tool will not magically find out what files and folders you want to include in your binary. It will obviously not include everything you have in your source or module's folder.
The way to tell which files you want to be included is a special //go:embed comment preceding the variable you want the files to be stored in.
So in your case you have to put the following comment before your templateFS variable:
//go:embed templates/*
var templateFS embed.FS
Also note that embedding only works if you import the embed package. This "naturally" happens in your case because you used the embed.FS type (which requires importing the embed package), but if you would include a file in a variable of string or []byte type, that wouldn't require importing embed, in which case you'd have to do a "blank" import like
import _ "embed"
More details are in the package doc of embed.
See related question: What's the best way to bundle static resources in a Go program?
Related
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).
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.
I have a main.go file that I worked on and now I'm trying to organize since it became a little lengthy. I want to create a new file, put some functions in it and then include it in main.go and use those functions. That new file will be in the same directory as main.go. Anybody have any idea how to do this?
As long as the go files are in the same package, you do not need to import anything.
Example:
project/main.go:
package main
import "fmt"
func main() {
fmt.Println(sayHello())
}
project/utils.go:
package main
func sayHello() (string) {
return "hello!"
}
To run: go run main.go utils.go or go run *.go
You don't have to do any including (importing). Just use the same package name in both files.
Old question, but no matter...
You can create go.mod file at the same directory you keep your source files with the help of following command:
go mod init main
This will create mod file for main package.
Each source file should start with package main directive.
After that you can build your project as follows:
go build .
And if you need build and run:
go run .
In trying to setup auto completion for C using clang complete in vim, and so far, when I'm inside a .c file, I kind of get auto completion when I hit ctrl+x,u. However it only displays some symbols.
None of the functions that's in the included headers appear in the auto complete popup box. It appears that only typedefs are showing?
The project structure is very simple:
$ tree -ap
.
├── [-rwxrw-r--] .clang_complete
├── [-rwxrw-r--] makefile
└── [drwxrw-r--] src
└── [-rwxrw-r--] FlightControl.c
1 directory, 3 files
I tried creating the .clang_complete file inside the project folder, that contains the following:
-I/.../Libraries/xpSDK/CHeaders/XPLM
I double checked the path to the XPLM headers, and it is correct.
Any ideas whats wrong?
During completion libclang tries to do its best by ignoring errors to present a user with the longest list of matches. I guess that you don't have XPLM_API macro defined. As it is used to declare every function in headers, you won't see any functions in completion list. Looking at defines in XPLMDefs.h I think that libclang gets Platform not defined! error (maybe even several times).
It should work if you define your platform for completion, I did this by adding -DLIN to .clang_complete file and completion works now.
So it doesn't seem to be an issue of vim or clang_complete, though it'd be nice to have a warning in such case.
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).