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).
Related
First of all, I don't know what I should call it, module, component, or library are all fitting for me, but gave all mixed results trying to figure this out.
Problem
I am working on a project in C, where the amount of files grew quite large, so I wanted to split it up a bit, both for ordering and make it look less cluttered.
I want a file structure that looks something like this:
root
├modules
│├module_foo
││├include
│││├module_foo_a.h
││││...
│││└module_foo_z.h
││├private_include
│││├a.h
││││...
│││└z.h
││├source
│││├module_foo_a.c
││││...
│││└module_foo_z.c
││└module_foo.h
│└module_bar
│ ├include
│ │├module_bar_a.h
│ ││...
│ │└module_bar_z.h
│ ├private_include
│ │├a.h
│ ││...
│ │└z.h
│ ├source
│ │├module_bar_a.c
│ ││...
│ │└module_bar_z.c
│ └module_bar.h
├main.c
├main.h
└CMakeLists.txt
Clarification
The goal of this would be that the private_include folders would be inaccessible by other modules and main, and the different modules would need to work (fairly) independent. Modules can include other modules, but this would need to be defined explicitly.
I also would like the CMake to be easy to modify, ideally only a single/couple line(s) to change for the modules used.
Pre research
As mentioned above, I have searched already, but the CMake documentation isn't meant for the people who just want to do some C coding.
When I searched for modules, almost all results were about the C++ modules and how to integrate them into CMake.
Components mostly gave results about the COMPONENTS keyword.
Library had the most results, however it still requires me to use #include "modules/module_foo/include/module_foo_a.h" from main, or #include "../../module_bar/include/module_bar_a.h" from module foo. The goal would be to have in both instances #include "module_foo_a.h".
Subdirectory isn't what I am looking for I believe, because that still makes it part of the root project. This is not what I want.
For the modules I currently have
project(foo)
add_library(${PROJECT_NAME} STATIC source/module_foo_a.c include/module_foo_a.h)
include_directories(private_include include)
link_libraries(bar)
target_include_directories(${PROJECT_NAME} INTERFACE include)
target_link_libraries(${PROJECT_NAME} PRIVATE bar)
I have included the header files in the add_library because one source I found said it helped with IDE's.
I don't remember why I made the target_include_directories interface, or the target_link_libraries private.
For my main CMake I have
project(foobar)
include_directories(include)
add_executable(${PROJECT_NAME} source/main.c)
target_link_libraries(${PROJECT_NAME} foo bar)
I believe I need to include bar again because of the private link in the module.
I don't even know if what I am searching for is actually possible, but I would really like to work with it this way, or close to this.
edit
Before I tried to add modules the folder structure looked something like this:
root
├include
│├foo_a.h
││...
│├foo_z.h
│├bar_a.h
││...
│├bar_z.h
│└main.h
└source
├foo_a.c
│...
├foo_z.c
├bar_a.c
│...
├bar_z.c
└main.c
This got very cluttered very quickly, hence why I want to change to modules.
As stated in my comment, the part that I have put above is what I have now. This does not make the modules easy to work with, as they don't provide short include names, both from outside the modules (main) and other modules (bar).
The little bits that I understand from CMake is that the functions have a 'normal' variant and a 'target' variant.
'Normal' is just for the current project, and 'target' is meant to also allow other CMakes to use those specified files/folders. This should however not work for the private_include folders, as they are only to be known to the module itself.
If I understand it correctly, including private_include in the 'target' variant would make it possible that you would do #include "a.h" or #include "private_include/a.h" in main, which is not what I want.
Problem description
I'm trying to write some text to the screen, but it feels like no matter what I do i always get:
Failed to load font "../assets/Font.ttf" (failed to create the font face)
A very simple example of the code.
#include<SFML/Graphics.hpp>
int main()
{
sf::Font font;
font.loadFromFile("../assets/Font.ttf");
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML works!");
sf::Text text("Hello World", font, 50);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.draw(text);
window.display();
window.clear();
}
return 0;
}
I'm building using Cmake and I expect that the problem lies in my CMakeLists files. I have one main and a sub-directory like: (Also very simple)
#Main
cmake_minimum_required(VERSION 3.0)
project(Sorting_Visualization)
add_subdirectory(src)
# Sub Directory
add_executable(${PROJECT_NAME} main.cpp)
find_package(SFML 2.5 COMPONENTS graphics audio REQUIRED)
target_link_libraries(${PROJECT_NAME} sfml-graphics sfml-audio)
File structure:
.
├── assets
│ └── Font.ttf
├── CMakeLists.txt
└── src
├── CMakeLists.txt
└── main.cpp
What I've tried
I read that similar problems occurred when people using Visual Studio linked release libs to their debug builds. There was suggested to link with ex. sfml-graphics-d for debug libs. However this doesn't seem to work for me and using dpkg libsfml-dev I don't see any files matching sfml-graphics-d. Should I maybe install these in some way?. Or is that some Visual Studio specific issue?
Further I think I was missing the Freetype dependecy at the time of installing SFML however running ldd on my sfml-graphics.so file it seem that freetype is found.
libfreetype.so.6 => /lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007f26fdca0000)
Lastly I was thinking that maybe the font I'm using is simply not compatible. But surely any true type font should be possible to use. Here is a link the font.
To summarize
I think I've read nearly everything there is online and I'm still completely stumped. The only thing left is my linking in Cmake which I found no clear resources on and I'm pretty new to working with libs. Some guidence would be greatly appreciated on this : )
Solution
I solved the problem and it was apparently the order in which I was finding the packages and linking them. I also have to always make all
This is working!
set(SOURCES main.cpp)
add_executable(${PROJECT_NAME} ${SOURCES})
find_package(SFML 2.5 COMPONENTS REQUIRED audio graphics )
target_link_libraries(${PROJECT_NAME} sfml-audio sfml-graphics)
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
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?
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.