C like #define in a source file

so in C we often have an include file that has our debug output routines.

in c we do this

      #define ENABLE_DEBUG. 0 //0. disables, 1 enables
      #include “debug_macros.h”

that debug macros file based on the define either a) has a bunch of debug functions or b) the #define macros turn the debug calls into null statements, please do not suggest dbg!() that has other issues on our embedded target

using #cfg() everywhere is a problem/messy because there would be hundreds of these in the module

we specifically enable/disable debug this way in the source file on purpose because a command line define is way to heavy handed it turns on far to many debug things in far to many files

and often you only want it enabled for a very few files anyway (the few you are working on at the moment)

i have seen the rust macro_rules! and think that is part of the solution but i still need to control the expansion some how on a per file basis

question #1 can some one point me to some examples?

question #2 how do you set a config option in a source file and specifically not the command line or cargo file

====
next is debug vrs release…. we make extensive use of the c language pargma to enable or disable optimization for a single file or two.

ie in an embedded environment we have very limited code/ram space - it fits if the code is optimized it does not if it is optimized. this also makes it impossibly hard to debug

so we have a macro OPTIMIZE_THIS_FILE() it basically turns on optimization for the file using a pragma

we place it at the top of every file and the code fits in the target :-> yea!

and for that one or two files you are working on (debugging) you comment out the macro and rebuild…. because everything else is optimized it fits! yea! and the one or two problem files while bigger… it fits! the rest are still optimized and the debugger has a reasonable experience.

how can i accomplish this with rust?

For logging the normal Rust log, is capable of that with feature flags.

For embedded you may want to look at defmt which is designed for logging in embedded.

For the optimization there's bad and news and a glimmer of good news.
The rust compilation unit is the crate not a file nor module so any parts that need different optimization levels would need to be in different crates, at least in stable rust.

In nightly there's a partial implementation to control optimization at the function level.

But it's been sitting in nightly for many years now, so what's there maybe good enough or maybe unusable to you, it's not a feature I've experimented with

1 Like

Sigh... like all things rust - it is not a very mature system. Maybe in 30-40 years it might.. or maybe it will go the way of ADA.. Once thought highly of but nobody uses it.

IMHO - There are many arrogant assumptions made by what I would call the RUST CORE like YOU SHALL DO IT OUR WAY AND ONLY OUR WAY ALL OTHER WAYS ARE STUPID AND DUMB, they don't get $PAID$ by my $CUSTOMER$

There are far far to many assumptions about the target, ie: You always have an OS - super loops are a thing rust developers believe otherwise, One does not always have a HEAP - rust developers believes otherwise .

These often conflict with rules/policies/procedures one must adhere to when $CUSTOMER$ lays down the $LAW$ if you want any form of $PAYMENT$.

For logging the normal Rust log, is capable of that with feature flags

So If I have several modules - each use the crate LOG a sub crate - can each module specify different configurations for their instance of the log module? Or is it the union of log requests.

For embedded you may want to look at defmt which is designed for logging in embedded.

yea that's not going to work well for me

it's interesting approach - it transmits a string index number instead of the string - that has to be reassembled on the host side. Cool idea.. I've done that before (ie: Place string constants in a 'noload section' at a unused memory address then transmit the string address instead of the text) the host side then extracts the string from the elf at that address.

That's not going to help me - the underlying transport varies by target - ie: sometimes it is UDP, other times it is a SPI interface - some targets have the SEGGER RTT, or ARM trace features.. Sometimes you are lucky if you have a dumb serial port that you share and need to intermix 'cmd/rsp' packets with log packets.

And - for my systems - the other side (the debug log receiver) - requires text strings only they cannot handle binary logs.

You set a global logger like provided by the env_logger crate. This global logger then can filter logs based on its own policy. The env_logger crate for example allows both global and per-module configurations using the RUST_LOG env var by default (though you can also provide a custom env var or an explicit configuration when registering it as global logger).

Edit: Didn't notice that you were on embedded.

Both having an OS and having a memory allocator are not assumptions that rust makes. You can do without both using #![no_std].

You can disable optimizations for individual crates using

[profile.release.package.my_crate]
opt-level = 0

in the root Cargo.toml.

2 Likes

If you want to roll your own, a simple log! macro that is totally off by default might look like this.

4 Likes

I'm curious why your C didn't use -Os or -Oz? Pragmas are not portable, and modern C compilers often ignore these kinds of pragmas altogether.

Like bjorn3 already hinted at, crates in Rust form the natural "units" of code. Rust crates are the closest equivalent we have to C compilation units.

1 Like

This style of configuration is possible if you really need it.

macro_rules! dprintln {
    ($(tt:tt)*) => {
        if DEBUG_ENABLE {
            println!($($tt)*);
        }
    }
}

This macro will print or not print depending on the value of a const named DEBUG_ENABLE in scope where it is used.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.