microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.19k stars 12.38k forks source link

Support conditional compilation #449

Open mpawelski opened 10 years ago

mpawelski commented 10 years ago

On codeplex this was a popular feature request:

https://typescript.codeplex.com/workitem/111 https://typescript.codeplex.com/workitem/1926

Personally I think preprocessor directives like #if, #elif, #else #endif with possibility to specify symbol to compiler would be very useful. And a way to mark function (or ambient function declaration) as Conditional (something like ConditionalAattribute in C#) would be great improvement too. I have lot's of console.log like function calls that decrease performance of my application and ability to easily remove all calls to this function would be great.

RyanCavanaugh commented 10 years ago

We'd like to gather some use cases on this. What do people want to use this for? There might be better solutions than conditional compilation depending on the application.

We would likely not implement a ConditionalAttribute-style attribute as it violates the "Don't depend on typechecking for emit" design goal.

For the console.log case, adding conditional compilation would be a large hammer for a small nail. Doing this no-op'ing at runtime would be essentially zero overhead (assuming that you would be writing a human-readable amount of stuff to the console in the debug case).

zpdDG4gta8XKpMCd commented 10 years ago

I can think of a few cases:

NoelAbrahams commented 10 years ago

Some use-cases:

// Production sources and keys        
   var foo = {
        root: "https://yyy.blob.core.foobar.net/",
        googlePlusKey: { id: "888888", key: "GIzdfBy" },
        facebookKey: { id: "444444444" }
     };

// Development sources and keys        
#if(DEBUG)
   var foo = {
        root: "https://xxx.blob.core.foobar.net/",
        googlePlusKey: { id: "458588", key: "BIzdfGy" },
        facebookKey: { id: "123219585123132" }
     };
#endif
#if(DEBUG)
       import foo = require('debug');
#else
       import foo = require('release');
#endif

function doFoo(){
    foo.someMethod();
}
#if(DEBUG)
       class Foo { doFoo(){ console.log('debug'); }  }
#else
       class Foo { doFoo(){ console.log('release'); }  }
#endif

var foo = new Foo();
CyrusNajmabadi commented 10 years ago

Having worked on the Roslyn API support for the C#/VB Preprocessor, I would def like to avoid bringing those huge complexity farms to TypeScript.

I am amenable though to other mechanism that might achieve the same goals, albeit with less flexibility.

       -- Cyrus

From: nabog [mailto:notifications@github.com] Sent: Sunday, August 24, 2014 3:41 AM To: Microsoft/TypeScript Subject: Re: [TypeScript] Support conditional compilation (#449)

Some use-cases:

// Production sources and keys

var foo = {

    root: "https://yyy.blob.core.foobar.net/",

    googlePlusKey: { id: "888888", key: "GIzdfBy" },

    facebookKey: { id: "444444444" }

 };

// Development sources and keys

if(DEBUG)

var foo = {

    root: "https://xxx.blob.core.foobar.net/",

    googlePlusKey: { id: "458588", key: "BIzdfGy" },

    facebookKey: { id: "123219585123132" }

 };

endif

if(DEBUG)

   import foo = require('debug');

else

   import foo = require('release');

endif

function doFoo(){

foo.someMethod();

}

if(DEBUG)

   class Foo { doFoo(){ console.log('debug'); }  }

else

   class Foo { doFoo(){ console.log('release'); }  }

endif

var foo = new Foo();

— Reply to this email directly or view it on GitHubhttps://github.com/Microsoft/TypeScript/issues/449#issuecomment-53187591.

mpawelski commented 10 years ago

I think compiler directives would be useful in scenario when you are targeting different platforms and want to have as much shared code as possible. Similar to what compiler directives are used today in C#. Many libraries (in .net framework code too) have code with conditional compiler directives to maximize code reuse. In JavaScript it's somewhat easier to detect if given feature is available but still there are situation when differences would be better handled by preprocessor directives for example for very different platforms (mobile, set-top-boxes, smart tv). It's sometimes easier to use compiler directive when there are differences in APIs and their behaviours.

We would likely not implement a ConditionalAttribute-style attribute as it violates the "Don't depend on typechecking for emit" design goal.

Are you afraid that sometimes it might be not clear that compiler have all type information about call (like in discussion about extension methods? Well, for people that use noImplicitAny this won't be a problem. We are also not doing any complex code transformation. Just removing some code calls so result JavaScript code would still be readable

Conditional compilation would definitely be useful in some situation. There might be other solutions but preprocessor directives are very simple to use and might be the best (and simplest) solutions.

But I must admit that the more I think about this feature, the more I consider it less important and would understand if compiler team would focus on other higher priority features.

RyanCavanaugh commented 10 years ago

To be clear, "noImplicitAny" is not "noAny"

[Conditional('debug')]
declare function debugPrint(s: string);
var d = { n: debugPrint };
var x: any = d.n; // Legal even with noImplicitAny
x('hello'); // Call to 'x' will not be conditionally compiled
mpawelski commented 9 years ago

It looks like "full" conditional compilation with preprocessor directives is a complex thing to implement, so maybe it's not worth the effort. But is it difficult to implement something like ConditionalAttribute so it would be easy to strip-out certain function call in code?

We would likely not implement a ConditionalAttribute-style attribute as it violates the "Don't depend on typechecking for emit" design goal.

A lot of minifiers allows to exclude console.log calls and this is often searched topic. I understand your resistance to this feature, but I believe many will find it useful. It won't be very general and often used feature but if the costs of introducing this feature is relatively small (it might not. I just guess. I don't implement compilers.) than I think it's worth considering to add.

About syntax. I guess we don't need special syntax for attributes, something like "special comment" will be fine for me if that would be easier to implement:

/// [Conditional("debug")]
declare function debugPrint(s: string);
s-panferov commented 9 years ago

I have just found another one good use case for this feature. I want to to enable JSON Schema validation for API calls. And, of course, I want it only for dev and test builds.

There are two aspects of the problem:

  1. I need to include modules with these schemas conditionally (I know that it can be done with async loading, but it is much more complex).
  2. I need an ability to enable/disable some statements that make Schema checks.

I'm writing a lot of code in Rust language and it has a suitable solution:

#[cfg(debug)]
mod test {
    // ...  
}
let my_directory = if cfg!(windows) {
    "windows-specific-directory"
} else {
    "unix-directory"
};

After this RFC will be done, #[cfg()] attribute will be allowed to use with any code block.

So there are good start steps for TS:

#[cfg(validate_schema)]
module schemas {
    export var schema1 = {
        // ...
    };  
}
export class UserApi extends ApiBase {
    static authenticate(login: string, password: string): Promise<{user: models.CurrentUser}> {
        var promise =  this.request('/api/auth', {
            type: 'POST',
            data: {
                login: login,
                password: password
            }
        });

        #[cfg(validate_schema)]
        promise = promise.then(validateSchema);

        return promise;
    }
}

What do you think?

paul-reilly commented 9 years ago

@s-panferov : it's certainly another solution, but there is potentially more code duplication than with standard pre-processor directives. I have to say that I don't understand the resistance to include them, since TypeScript can leverage the power of the compiler. It doesn't seem logical to have to jump through workarounds that scripted languages by nature need when there is an obvious and simple solution available.

zpdDG4gta8XKpMCd commented 9 years ago

@paul-reilly budget limit a good excuse for resistance, although I am in your team and i say there are numerous ways to use it, although many of them can be solved just by leveraging constants say we declare const debug = false which gives the runtime a strong hint to optimise things like if (debug) {...} up to exclusion which, at least for me, covers 90% of use cases On Dec 11, 2014 5:33 PM, "paul-reilly" notifications@github.com wrote:

@s-panferov https://github.com/s-panferov : it's certainly another solution, but there is potentially more code duplication than with standard pre-processor directives. I have to say that I don't understand the resistance to include them, since TypeScript can leverage the power of the compiler. It doesn't seem logical to have to jump through workarounds that scripted languages by nature need when there is an obvious and simple solution available.

Reply to this email directly or view it on GitHub https://github.com/Microsoft/TypeScript/issues/449#issuecomment-66701695 .

fletchsod-developer commented 9 years ago

How about web.config somehow? My company said it's a bad practice to use #Debug or #Release cuz it deal with processors, so my company require us to use web.config for that purpose. (The trasnformation to web.config takes care of it).

jez9999 commented 9 years ago

I would definitely like to see conditional compilation in TypeScript. I have a use case for it right now, where I'd like to enable some JavaScript code for when developers run our application, but not include the code at all when it is deployed. Conditional compilation would be ideal for this.

agnauck commented 9 years ago

for me it would be very useful for:

1) targeting different platforms, like browser vs node 2) unit testing. Sometimes it simplifies unit testing a lot when I can just add public properties or functions to a classes with a #TEST condition.

fletchsod-developer commented 9 years ago

At my company, we're discourage from using any compilation option in source code (cuz it deals with CPU) and we're required to use the config file (App.Config, Web.Config, .Config.Debug, .Config.Release) instead. So, it's a moot point here when it come to some business and not personal preferences.

AbubakerB commented 9 years ago

Is there any update on this? I know its kind of a pain to implement . . . but its also very useful for us typescriptters :) .

mhegazy commented 9 years ago

We need a proposal for this feature. Pre-processor directives (i.e.#ifdefs) are not desirable. But something along the lines of Conditional in C# would be more like it. Either ways we need a proposal for this to move it to the next stage (i.e Accepting PRs).

tinganho commented 9 years ago

Right now, this is a deal breaker for me in a project I'm working on.

I helped developed an in-house isomorphic framework that could be ran on server and the client. So in AMD we use a lot of conditional imports and conditional executions.

defined(function(exports, require) {
  if (insServer) {
    // require and do something
    // do something
  }
  else if (inClient) {
    // require and do something
    // do something
  }
  // do common stuff
});

We haven't been able to switch to TS because there are no mechanism that deal with our problem.

I think there many other projects that could benefit from this. At least many cross platform frameworks need this feature.

tinganho commented 9 years ago

I'm also not sure if the conditional in C# would fit our use case.

basarat commented 9 years ago

We haven't been able to switch to TS because there are no mechanism that deal with our problem.

as a workaround why not have a different ambient .js file for server vs. client

karldodd commented 8 years ago

In the msdn blog post Angular 2: Built on TypeScript:

We have worked with the Angular team to design a set of new features that will help you develop cleaner code when working with dynamic libraries like Angular 2, including a new way to annotate class declarations with metadata. Library and application developers can use these metadata annotations to cleanly separate code from information about the code, such as configuration information or conditional compilation checks.

So, isn't Angular 2 a use case? :)

Also I'd like to provide my use case: we need to compile different versions of our js library. Some versions implement a feature in a powerful complex way, while some versions implement the feature in a very simple way (size is smaller and size matters).

jameskeane commented 8 years ago

@aleksey-bykov I agree with you here.

Ideally I'd like to see something like the closure compiler, where you can provide compile time definitions: closure-compiler --define "DEBUG=true"

battmanz commented 8 years ago

I have a use case for this. I currently have a working iOS and Android app built on the Ionic Framework. The app uses cordova plugins to take advantage of the native capabilities of the phone or tablet on which it is run.

However, we now want to reuse the same code to build a single-page website that can run on a standard desktop browser. We cannot call cordova plugins from the desktop. In certain places, we'll have different code for the app version vs the desktop version. It would be nice if we could conditionally compile either the app version or the desktop version based on some symbol.

jameslong commented 8 years ago

My use case (as mentioned by others) is when writing isomorphic code targeting different platforms. e.g. node/client. It'd be great to have a solution to this.

domchen commented 7 years ago

Hi guys, check out this project : https://github.com/domchen/typescript-plus . It is an enhanced version of the original typescript compiler, which provides conditional compilation.

You can use the defines option to declare global variables that the compiler will assume to be constants (unless defined in scope). Then all the defined global variables will be replaced with the corresponding constants. For example:

tsconfig.json:

{
    "compilerOptions": {
        "defines": {
            "DEBUG": false,
            "LANGUAGE": "en_US"
        }
    }
}

TypeScript:

declare var DEBUG:boolean;
declare var LANGUAGE:string;

if (DEBUG) {
    console.log("DEBUG is true");
}

console.log("The language is : " + LANGUAGE);

function someFunction():void {
    let DEBUG = true;
    if (DEBUG) {
        console.log("DEBUG is true");
    }
}

JavaScript:

if (false) {
    console.log("DEBUG is true");
}

console.log("The language is : " + "en_US");

function someFunction() {
    var DEBUG = true;
    if (DEBUG) {
        console.log("DEBUG is true");
    }
}

As you can see, the second if(DEBUG) in someFunction is not replaced because it is defined in scope.

Note that the compiler does not dropping the unreachable code, because it is can be easily done by other tools like UglifyJS or Google Closure Compiler.

zpdDG4gta8XKpMCd commented 7 years ago

here is a use case:

i wish i could make code broken for one single developer in my team, so that it doesn't crash the build but whoever is mentioned there won't be able to compile it unless the issue is addressed

#if AB // <-- my initials as a compile time constant that only set on my machine
 !!! please fix what's below !!!
#endif
sebas86 commented 7 years ago

Conditional compilation can be done with existing tools.

I use two separated files with this same declarations but different values:

I also has two tasks in build system, both tasks refers to some shared code but first also has defined path to /src/conditional/dev when second one use /src/conditional/release.

With that TypeScript will transpile any if-else statement where AppConstants.DEBUG_MODE is used to: if (0) { ... } else { ... } or if (1) { ... } else {...} and code like this can be easily optimized with uglifyjs…

PatrLind commented 7 years ago

I just put this here if someone finds it useful. I had a lot of problems regarding this on a multi platform typescript project I am working on. I use webpack as the final bundler and I created a small webpack loader module to help me conditionally turn on and off typescript code. Basically I can write something like this:

//#ifdef PLATFORM_A
import { stuff } from './platform-specific-code/platform_a'
//#else
import { other_stuff } from './platform-specific-code/platform_b'
//#endif

or maybe like this with dynamic imports:

      //#ifdef __EXEC_ENV_BROWSER
      const { PlatformHandlerBrowser } = await import("./browser/platform-handler-browser");
      return new PlatformHandlerBrowser();
      //#endif
      //#ifdef __EXEC_ENV_NODE
      const { PlatformHandlerNode } = await import('./node/platform-handler-node');
      return new PlatformHandlerNode();
      //#endif
      //#ifdef __EXEC_ENV_QT
      const { PlatformHandlerQt } = await import("./qt/platform-handler-qt");
      return new PlatformHandlerQt();
      //#endif

Anyway... if you find it useful it is available here: https://github.com/Ramzeus/webpack-preprocessor-loader

Trucoto commented 7 years ago

@sebas86 That's not really conditional compilation. If I have code that only compiles under certain circumstances (conditions), typescript will attempt to compile all if/else blocks and it will fail.

hanchan07 commented 6 years ago

I am also interested in something like this. Our use case being TS requires a constructor for our AngularJs classes, but they are not needed in the actual .js files. When transpiling against ES6 the constructor gets put in to the .js file and breaks our buildscripts. Unfortunately some things are out of my control with the framework the company has implemented, and I cant find a way around this. However removing the constructor from the .js files works fine with the build.

If there was a way to tell the transpiler to ingore lines, or blocks of code, maybe something like how you can tell eslint to ignore a line with a comment or something? I wouldn't care as much as how it would be implemeneted, but would love the functionality to do so.

mindplay-dk commented 6 years ago

My use-case: I'm writing a JSX/DOM patcher (for fun and practice) and it has a lot of internal decision-making about whether to recycle/discard existing elements, reposition or leave elements in-place, etc.

Writing tests for this is extremely difficult, because there isn't always any direct evidence in the DOM afterwards of the precise internal decision-making steps - however, these are very important, and testing whether it's internally making the right decisions is much simpler than testing the results and/or side-effects, and in some cases, not possible at all.

I went looking for this feature because I was hoping to use conditional compilation to maintain a log of the internal decision-making steps, and then write tests that make assertions about the decisions that were made. I could of course inject an optional logger of some sort, but this being a minimalist JSX/DOM patcher, file-size and performance are both critical factors.

So for now, I'm doing a lot of console.log() while testing the internal logic of this thing, and manually validating the decisions on-screen. I'm of course also writing tests for the resulting effects of calling this function, and I'm hoping that this well be enough, once I'm satisfied with the decision-making logic and erase the console.log() statements - however, at that point, it becomes extremely risky to change/refactor the decision-making logic.

With compiler conditionals, I could have made this internal logging-feature available for testing only.

Of course, I can still accomplish something similar using a workaround - for example, I could flag certain lines with a trailing comment like // ERASE, and then have a search-and-replace built into a build-script that removes parts of the code after running the tests.

aalbericio commented 6 years ago

Hello,

Our usecase is the same: dealing with console.logs in dev mode that we don't want to be effective in production.

MarcWeber commented 6 years ago

There are many cases, haxe, haskell, c/cpp all have it. In my case I need a 'compile with mocking' and 'compile without mocking' flag.

oliverjanik commented 6 years ago

Here's our use case. This feature would greatly simplify our lives.

We have a common code-base targeting the browsers and Cordova hybrid apps. Parts of our code base only deal with one or the other.

We would love if we could leave certain parts out for different builds. They also pull in different dependencies. So when building for the web we have to pull in Cordova dependencies otherwise TS complains about missing types.

qfox commented 5 years ago

It is possible to check code in node (with --check flag) and would be great to have similar functionality in tsc.

zpdDG4gta8XKpMCd commented 5 years ago

coming back to https://github.com/Microsoft/TypeScript/issues/449#issuecomment-261291540, we need it so bad that we gonna use a local git config to store initials and a custom tslint rule to flag the places marked by those initials in code

// @ts-ignore: FIX: AB: // <-- tslint will flag this place for AB (me)
function xxx() { // .. some ill code here
penguin020 commented 5 years ago

CASE: I need to include moduleId: module.id in a Angular \@Component decorator when I am in DEV mode, but not in Prod.

see https://stackoverflow.com/q/55854688/279393

tohagan commented 5 years ago

Webpack workarounds:

MarcWeber commented 4 years ago

I have another case:

If you have a simple routing:

Array<{
   title: ....
  component: ....
  sitemap_content: ....
}>

Then the sitemap_content should not be send to client, doesn't make sense.

The if (static-flag) doesn't work either. If you try using it you might get typing errors

Well, fine... You could be using a dictionary instead and create a new type for the sitemap forcing you to think about each route ... The problem then is that you loose ordering -> Yes you can create another list 'ordering' .. but then you have to edit 2 files and 2 places rather than copy paste.

Then I feel serving the compiler, not my projects.

sebas86 commented 4 years ago

@sebas86 That's not really conditional compilation. If I have code that only compiles under certain circumstances (conditions), typescript will attempt to compile all if/else blocks and it will fail.

But it works and for me and was good enough when I need something similar to preprocessor. Sometimes you must work with what you actually have instead waiting. This has some positives and negatives as well. Positive is that it's a regular code - your IDE see always whole code and you can safely refactor whole code base, negative is that your IDE also always see whole code and some tricks are not allowed, for example you can't duplicate some symbols or cut off whole class definitions without getting errors or warning...

Moreover please don't think of it as excuses for lack of real preprocessor. It is just a hint for others which already need a working solution without waiting for something else.

c0nf1gur4t0r commented 3 years ago

Well, I can't believe that TS doesn't have a feature like so 😑

My problem is that, in a code refactoring, I need to make this snippet below run only in development environment (process.env.NODE_ENV = 'development') without an 'if' or something, inside an 'global.d.ts'.

declare global {
  namespace NodeJS {
    interface Global {
      signIn(hasPermission: boolean): string;
    }
  }
}
martin-braun commented 3 years ago

@scandeiro Ye, it's such a shame that this was forgotten, been 7 years, now ...

CyrusNajmabadi commented 3 years ago

There's a difference between "being forgotten" and "there's no design that's been found that is felt to be acceptable given all the goals/constraints in the language design space" :)

martin-braun commented 3 years ago

There's a difference between "being forgotten" and "there's no design that's been found that is felt to be acceptable given all the goals/constraints in the language design space" :)

Fair point. One could argue that this is a challenge that can be solved by a huge entity such as Microsoft within 7 years, though, so it maybe feels "forgotten". I'm still grateful for TypeScript even when this never gets implemented.

It is, what it is.

c0nf1gur4t0r commented 3 years ago

There's a difference between "being forgotten" and "there's no design that's been found that is felt to be acceptable given all the goals/constraints in the language design space" :)

Yeah! Anyway, it's a simple feature to be handled on tsc...just saying 🤔

GaryChangCN commented 3 years ago

anything new?

buksy90 commented 2 years ago

Hi, I'd like to share why I would support some conditional compilation, here are two examples that are currently hard to resolve:

  1. Conditional import / export Let's say I have a following helper file helpers.ts
function setQueryParams(url: string, params: Record<string, string>): string { /* implementation */ }
function refreshTab(): void { /* implementation */ }

export { setQueryParams, refreshTab }

and then I have following consumer main.ts

import { setQueryParams } from './helpers';

function foo() {
  /* some code that uses setQueryParams() */
}

when writing test for main.ts, I'm currently not able to easily stub the setQueryParams function because of the way it is imported. Solution would be to change helpers.ts to export object of functions

const helpers = { setQueryParams, refreshTab };
export default helpers;

so then I can easily stub properties of the object being exported as default. But I do not want to do this as I may have many functions in the helper file and this way of export prevents from threeshaking unused functions. So I would like to be able to conditionally switch between these export mechanisms to be able to easily test the code but at the same time to be able to eliminate unused code.

  1. Another example would be similar and it is again for dead code removal. Sometimes to make it easier to arrange a test I create public setters or getters of private properties of class. I have an utility function preventNonTestEnv() that throws an error if it's called in other than test environment and this function is called at the beginning of these setters/getters. It helps to prevent using those methods outside of tests in production code, but still, I'd rather see those functions gone in production code and that would be something easy to achieve with conditional compilation.

So basically, in my case, I would need different code output based on the current NODE_ENV

mtomassoli commented 2 years ago

In my opinion, what we really need is not conditional compilation, but conditional typechecking to avoid type errors in code that is excluded from execution.

dyst5422 commented 2 years ago

Agreed with @mtomassoli. Typescript should in no way alter runtime behavior - very clearly a stated goal - and there are a hundred different ways to enforce that at runtime and strip it out with other pre-processors. What WOULD be useful is to indicate to the compiler that the types may be a bit different based on the platform.

Example:

You have some code that interacts with data in a few different ways:

doThingWithString(stuff: string);
doThingWithBlob(stuff: Blob);// <- invalid in Node b/c Blob doesn't exist
doThingWithBuffer(stuff: Buffer);// <- invalid in browser b/c Buffer doesn't exist
doThingWithStream(stuff: ReadStream);

Now if the compiler knows that based on the platform, one exists and the other doesn't. Having the type checked essentially hide the invalid function based on platform without changing the actual JS code output seems like its inline with the Typescript model and scoped appropriately.

This is simply a concrete use case for a typing emit/typecheck directive.

Going to be honest though, I would not put this anywhere near the top of the backlog. The use cases are just not sufficient and its easy enough to just not use those apis

NumbGnat commented 1 year ago

I'm writing this as I'm sitting down to refactor a sizeable TypeScript project and optimize performance by removing the processing of debug logging during production use of the Google Apps Script application. Those of us using CLASP to transpile and push our projects to Google Apps Script projects, really don't have a good option to remove development/debug/logging code during the publish process.

Consider the following snippit of code...

Toast("Locating Destination Coordinates...", 60, true);
WriteLog(LOGGING_LEVEL.DEBUG, "Locating Destination Cell...");
WriteLog(LOGGING_LEVEL.DEBUG, "start = [" + start.x + "," + start.y + "]");
WriteLog(LOGGING_LEVEL.DEBUG, "end = [" + this.mSheet.getLastColumn() + "," + this.mSheet.getLastRow() + "]");
WriteLog(LOGGING_LEVEL.DEBUG, "-----");

Our logging function already makes a determination whether to log based on a global constant, so we have a way to limit logging based on our needs. But Sheet.getLastRow() is process intensive, so I'd rather not incur that if the message is ultimately not going to be logged.

My only option to reduce processing overhead is to go through the entire app and wrap all of our logging code inside...

if (LOG_LEVEL >= LOGGING_LEVEL.DEBUG) {
  ...
}

As I'm doing this, I can't help but think that I'd rather be putting in transpile-time directives that tell TypeScript to simply remove the block of code, so we don't even incur the cost of the logical comparison altogether.

#ifdef (DEBUG)
  ...
#endif

To me, it really doesn't matter what type of notation is used. It just needs to be something I can adorn my code with, that tells the transpiler not to include that block in the final JavaScript. It's already doing a bunch of script manipulation, to make sure the resulting output can be executed by Google Apps Script. I can't imagine this would be all that difficult to do.

CyrusNajmabadi commented 1 year ago

I can't imagine this would be all that difficult to do.

conditional compilation is one of the most complex things i've seen in every compiler i've worked on. It is probably not as simple as one would like :)