I'm working on a project which should target wasm, but some functionality will not be supported.
It looks like I can conditionally include a function in this way:
#[cfg(target_arch = "wasm32")]
fn my_func() { ... }
Or conditionally call it like so:
if cfg!(target_arch = "wasm32") {
my_func();
} else {
...
}
But how can I conditionally exclude a declaration or a block of code on wasm?
I.e. I am looking for something similar to #ifndef in c macros:
#ifndef WASM
native_only_func();
#endif
To negate condition use #[cfg(not(condition))]. You can read more about conditional compilation in this section of The Rust Reference.
Related
If I instantiate a lambda somewhere (and the compiler doesn't inline it), I can find a string showing where the lambda is located in my c++ code like this:
... ?AV<lambda_1>#?0??MyFunction#MyScopedClass#MyNamespace##SAXXZ# ...
I don't want this information in the executable, as it could give away important names of classes and functions.
All kinds of output debug information are turned off. If I use a normal function instead, the final executable doesn't have this information, so manually converting all lambdas into normal functions would "fix it". But what's the best way to handle this? Can we tell the compiler to transform lambdas into normal functions?
UPDATE: I tested with other compilers: g++ and clang. They both leave the same references. I also found another unanswered question about this Gcc - why are lambdas not stripped during release build Please don't come with the "why do you care about a few symbols anyway".
Here's some code you can test with:
#include <iostream>
#include <functional>
class MyUnscopedClass
{
public:
MyUnscopedClass(const std::function<void(int x)>& f) :
f(f)
{
}
std::function<void(int x)> f;
};
namespace MyNamespace
{
class MyScopedClass
{
public:
static void temp1(int x)
{
std::cout << x * (x + 1);
}
static void MyFunction()
{
//MyUnscopedClass obj(temp1); // no symbols
MyUnscopedClass obj([](int x) // ?AV<lambda_1>#?0??MyFunction#MyScopedClass#MyNamespace##SAXXZ#
{
std::cout << x;
});
obj.f(23);
}
};
}
int main()
{
MyNamespace::MyScopedClass::MyFunction();
}
With the help of #dxiv in the comments, I found the problematic setting.
Configuration Properties > General > C++ Language Standard
can't be, for some reason,
Preview - Features from the Latest C++ Working Draft (std:c++latest)
So I set it to the second most recent one
ISO C++17 Standard (std:c++17)
and I get a random identifier instead.
AV<lambda_f65614ace4683bbc78b79ad57f781b7f>##
I'm still curious how this identifier is chosen though.
Suppose I have the following code inside a module:
struct A{
}
#[macro_export]
macro_rules! profile {
($variable_name:tt, $expression:expr) => {
let a = A{};
}
}
so it'd be in a/a.rs, to the side of a/mod.rs which exports a::A and also exports the macro.
The problem is that when I use this macro on other modules like b/b.rs, I'd have to use super::a::A before using the macro.
I could change let a = A{}; on the macro to let a = self::a::A{};. However, it'd not work on all modules, and certainly not for users of this library that use this library in their code.
How can I specify let a = something::something::A{}; in a way that it works anywhere inside my library as well for users of this lib?
In declarative macros specifically, you can use the $crate metavariable to reference the crate the macro is defined in, and then use the absolute path of the item. This will work both inside and outside of your library. For example, if your struct A is defined in your library at the path module_a::module_b::A, you would use:
struct A{
}
#[macro_export]
macro_rules! profile {
($variable_name:tt, $expression:expr) => {
let a = $crate::module_a::module_b::A{};
}
}
Here's the relevant section of the Rust reference guide.
I know similar questions have been asked, but none address this issue. I want to create a globals struct and initialize it with default values. I implemented it as below, but the project won't build.
I've tried everything I can think of, most notably moving the "extern" declaration of *gxg in and out of the header guard and changing the struct to a class, but get the same results: the project won't build because of duplicate symbols for the globals constructor. It builds if I don't use it in more than one .cpp file, or if I don't include a constructor or destructor in the struct's implementation file.
// globals.hpp
#ifndef globals_hpp
#define globals_hpp
struct gxGlobals{
double radius;
bool easement;
gxGlobals(); // constructor
} ;
extern "C" gxGlobals *gxg;
#endif /* globals_hpp */
—————————————
// globals.cpp
#include "globals.hpp"
gxGlobals::gxGlobals():
radius(24),
easement(false)
{};
———————————
// main_file.cpp
#include "globals.hpp"
gxGlobals *gxg = new gxGlobals();
———————————
// other_file.cpp
#include "globals.hpp"
// ERROR: Duplicate symbol gxGlobals::gxGlobals()
I can include globals.h in one file, but not in two or more. It also works if I remove the self-initialization in the .cpp file.
There are too many members in the actual struct to make an initializer list practical, so my last option is a function that runs on startup that plugs all of the default values in. Am I mistaken that this should work?
If I define structs at the module level, I can reference not-yet defined structs.
struct S {
ComesLater c;
}
struct ComesLater {}
But If I do the same inside an unittest or a function block, it doesn't work:
unittest {
struct S {
ComesLater c;
}
struct ComesLater {}
}
Error: undefined identifier 'ComesLater'
Why is that? How can I get order-independent declarations inside functions? Is there some kind of forward-declaration in d? I need this because I generate structs using mixin and ordering the declarations in the order of their inner-dependencies would be quite some effort, sometimes impossible, if there are circularly referencing structs. (using pointers.)
Declarations inside functions, unittests, or anywhere else that statements can actually be executed are indeed order-dependent because their values may depend on the code before them running. Think of a local variable:
int a;
writeln(a);
a = b;
int b = get_user_line();
If order wasn't important there, when would the two functions get called? Would the user be asked for a line before the writeln as the declarations are rewritten?
The current behavior of making b an undefined variable error keeps it simple and straightforward.
It works independent of order in other contexts because there is no executable code that it can depend on, so there's no behavior that can change if the compiler needs to internally think about it differently.
So:
How can I get order-independent declarations inside functions?
Change the context such that there is no executable code... put it all inside another struct!
void main() { // or unittest { }
struct Holder {
static struct S {
C c;
}
static struct C {}
}
}
Since execution happens around the holder and doesn't happen inside it, the order of declaration inside doesn't matter again. Since you can define almost anything inside a struct, you can use this for variables, functions, other structs, and so on. Basically all you have to do is wrap your existing code inside the struct Holder {} brackets.
By making everything static inside, you can just use it like a container and reference the stuff with Holder.S, etc., on the outside.
I'm trying to declare a map in a separate file, and then access it from my main function.
I want Rust's equivalent (or whatever comes closest) to this C++ map:
static const std::map<std::string, std::vector<std::string>> table = {
{ "a", { "foo" } },
{ "e", { "bar", "baz" } }
};
This is my attempt in Rust.
table.rs
use std::container::Map;
pub static table: &'static Map<~str, ~[~str]> = (~[
(~"a", ~[~"foo"]),
(~"e", ~[~"bar", ~"baz"])
]).move_iter().collect();
main.rs
mod table;
fn main() {
println(fmt!("%?", table::table));
}
The above gives two compiler errors in table.rs, saying "constant contains unimplemented expression type".
I also have the feeling that the map declaration is less than optimal for the purpose.
Finally, I'm using Rust 0.8.
As Chris Morgan noted, rust doesn't allow you to run user code in order to initialize global variables before main is entered, unlike C++. So you are mostly limited to primitive types that you can initialize with literal expressions. This is, afaik, part of the design and unlikely to change, even though the particular error message is probably not final.
Depending on your use case, you might want to change your code so you're manually passing your map as an argument to all the functions that will want to use it (ugh!), use task-local storage to initialize a tls slot with your map early on and then refer to it later in the same task (ugh?), or use unsafe code and a static mut variable to do much the same with your map wrapped in an Option maybe so it can start its life as None (ugh!).