Thread overview
CTFE and -betterC
Mar 13, 2018
Xavier Bigand
Mar 14, 2018
rikki cattermole
Mar 15, 2018
Flamaros
Mar 16, 2018
Xavier Bigand
Mar 16, 2018
Xavier Bigand
March 14, 2018
As I am trying to do a dll that acts exactly like one written in C, I am trying to compile my code with the -betterC option. So I would not need the DllMain function.

I am not sure that I use the best syntax for my CTFE function to be able to make it works with the option -betterC and to maintain it after.

In particular I have following issues (my code is at the end of message) :
 * startsWith function doesn't compile with -betterC
 * can't put static before the first foreach
 * don't really now how to factorize small expressions (oglFunctionName , oglFunctionName,...)
 * how to make the code I generate less polluted by conditions and iterations? Certainly by naming some previously computed parts with alias?
 * after that how to see the generated result and debug?

Thank you in advance for any help.

module api_entry;

import std.stdio : writeln;
import std.algorithm.searching;

import missing_ogl;

import std.traits;
import std.meta;

static string implementFunctionsOf(string Module, bool removeARB = false)()
{
    import std.traits;
    import std.regex;
    import std.conv;

    mixin("import " ~ Module ~ ";");

    string	res;

    res ~= "extern (C) {\n";

    foreach (name; __traits(allMembers, mixin(Module)))
    {
        static if (name.startsWith("da_")
                   && mixin("isCallable!" ~ name))
        {
            alias derelict_oglFunctionName = Alias!(name[3..$]);
            alias oglFunctionName = derelict_oglFunctionName;
            alias returnType = Alias!(ReturnType!(mixin(name)).stringof);
            alias parametersType = Alias!(Parameters!(mixin(name)).stringof);

            static if (removeARB && name.endsWith("ARB"))
                oglFunctionName = oglFunctionName[0..$ - 3];

            res ~=
                "export\n" ~
                returnType ~ "\n" ~
                oglFunctionName ~
                parametersType ~ "\n" ~
                "{\n" ~
                "    writeln(\"" ~ oglFunctionName ~ " is not specialized\");\n";

            // Forward the call to the driver (with arguments and return the
            // value of the forward directly)
            res ~= "import " ~ Module ~ ";";

            // For a reason I do not understand the compiler can not
            // compile with returnType
            static if (ReturnType!(mixin(name)).stringof == "int function()")
                res ~=
                    "    alias extern (C) " ~ returnType ~ " returnType;\n" ~
                    "    return cast(returnType) ";
            else if (returnType != "void")
                res ~=
                    "    return ";
            res ~=
                "    " ~ Module ~ "." ~ derelict_oglFunctionName ~ "(";
            foreach (i, parameter; Parameters!(mixin(name)))
            {
                if (i > 0)
                    res ~= ", ";
				// We use the default parameter name variable "_param_x" where x
				// is the index of the parameter starting from 0
                res ~= "_param_" ~ to!string(i);
            }
            res ~=
                ");";

            res ~=
                "}\n";
        }
    }

    res ~=
        "}\n";
    return res;
}


mixin(implementFunctionsOf!("derelict.opengl3.functions"));
mixin(implementFunctionsOf!("derelict.opengl3.deprecatedFunctions"));
March 14, 2018
You will still need DllMain, that is a platform requirement.
March 15, 2018
On Wednesday, 14 March 2018 at 01:17:54 UTC, rikki cattermole wrote:
> You will still need DllMain, that is a platform requirement.

I am not sure about that because when DllAnalyser don't see it in the opengl32.dll from the system32 directory. And the documentation indicate that it is optional.

I finally choose to put the entry points generation in a sub-project that put them in a d file, like that it is easier to make the CTFE working and will be much better for the debugging and compilation time.

So I have also some few other questions :
 - Is it a bug that ctRegex doesn't with the return of allMembers?
 - What is the status of the new CTFE engine?
 - Will CTFE be able to write files or expose a way to see to resulting generated code for a debug purpose?
 - Is there a reason why CTFE is impacted by the -betterC option?

March 16, 2018
Le 15/03/2018 à 01:09, Flamaros a écrit :
> On Wednesday, 14 March 2018 at 01:17:54 UTC, rikki cattermole wrote:
>> You will still need DllMain, that is a platform requirement.
>
> I am not sure about that because when DllAnalyser don't see it in the opengl32.dll from the system32 directory. And the documentation indicate that it is optional.
>
> I finally choose to put the entry points generation in a sub-project that put them in a d file, like that it is easier to make the CTFE working and will be much better for the debugging and compilation time.
>
> So I have also some few other questions :
>  - Is it a bug that ctRegex doesn't with the return of allMembers?
>  - What is the status of the new CTFE engine?
>  - Will CTFE be able to write files or expose a way to see to resulting generated code for a debug purpose?
>  - Is there a reason why CTFE is impacted by the -betterC option?
>


I actually found token strings, but I can't figure out how to cascade them, it is even possible?
I tried things like that :

enum loadSystemSymbolsCode = q{
version (Windows)
{
    extern (Windows)
    void loadSytemSymbols()
    {
        import core.sys.windows.windows;

        immutable string dllFilePath = "C:/Windows/System32/opengl32.dll";

        auto hModule = LoadLibraryEx(dllFilePath, null, 0);
        if (hModule == null)
        {
            return;
        }
        writeln(dllFilePath ~ " loaded.");

        "%SYSTEM_BINDINGS%"
    }
}
};

enum moduleCode = q{
module api_entry;

import std.stdio : writeln;
import derelict.util.wintypes;

export extern (C)
{
    mixin(loadSystemSymbolsCode);
}
};

string getLoadSystemSymbolsCode(string bindinsCode)()
{
    return loadSystemSymbolsCode.replace("%SYSTEM_BINDINGS%", bindinsCode);
}

string getModuleCode(string loadSystemSymbolsCode)()
{
    return moduleCode.replace("%LOAD_SYSTEM_SYMBOLS%", loadSystemSymbolsCode);
}

void    main()
{
    import std.stdio : File;

    auto file = File("../opengl32/src/api_entry.d", "w");

    file.writeln(
        getModuleCode!(
            getLoadSystemSymbolsCode!("test;")())
        );
}

Is there some materials for learning to do this kind of things with CTFE?
March 17, 2018
Le 16/03/2018 à 22:58, Xavier Bigand a écrit :
> Le 15/03/2018 à 01:09, Flamaros a écrit :
>> On Wednesday, 14 March 2018 at 01:17:54 UTC, rikki cattermole wrote:
>>> You will still need DllMain, that is a platform requirement.
>>
>> I am not sure about that because when DllAnalyser don't see it in the opengl32.dll from the system32 directory. And the documentation indicate that it is optional.
>>
>> I finally choose to put the entry points generation in a sub-project that put them in a d file, like that it is easier to make the CTFE working and will be much better for the debugging and compilation time.
>>
>> So I have also some few other questions :
>>  - Is it a bug that ctRegex doesn't with the return of allMembers?
>>  - What is the status of the new CTFE engine?
>>  - Will CTFE be able to write files or expose a way to see to resulting generated code for a debug purpose?
>>  - Is there a reason why CTFE is impacted by the -betterC option?
>>
>
>
> I actually found token strings, but I can't figure out how to cascade them, it is even possible?
> I tried things like that :
>
> enum loadSystemSymbolsCode = q{
> version (Windows)
> {
>     extern (Windows)
>     void loadSytemSymbols()
>     {
>         import core.sys.windows.windows;
>
>         immutable string dllFilePath = "C:/Windows/System32/opengl32.dll";
>
>         auto hModule = LoadLibraryEx(dllFilePath, null, 0);
>         if (hModule == null)
>         {
>             return;
>         }
>         writeln(dllFilePath ~ " loaded.");
>
>         "%SYSTEM_BINDINGS%"
>     }
> }
> };
>
> enum moduleCode = q{
> module api_entry;
>
> import std.stdio : writeln;
> import derelict.util.wintypes;
>
> export extern (C)
> {
>     mixin(loadSystemSymbolsCode);
> }
> };
>
> string getLoadSystemSymbolsCode(string bindinsCode)()
> {
>     return loadSystemSymbolsCode.replace("%SYSTEM_BINDINGS%", bindinsCode);
> }
>
> string getModuleCode(string loadSystemSymbolsCode)()
> {
>     return moduleCode.replace("%LOAD_SYSTEM_SYMBOLS%", loadSystemSymbolsCode);
> }
>
> void    main()
> {
>     import std.stdio : File;
>
>     auto file = File("../opengl32/src/api_entry.d", "w");
>
>     file.writeln(
>         getModuleCode!(
>             getLoadSystemSymbolsCode!("test;")())
>         );
> }
>
> Is there some materials for learning to do this kind of things with CTFE?

I feel my self little stupid, I don't need the " in the token string with the %WordToReplace%. So I think that the magic will happen.