将make.c移植到D

沃尔特·布赖特Walter Bright)是D编程语言的“仁慈终身独裁者”,也是Digital Mars的创始人他在开发多种语言的编译器和解释器方面拥有数十年的经验,其中包括第一个本机C ++编译器Zortech C ++。他还是《帝国》的创建者,《帝国》是西德·迈耶《文明》的主要灵感来源。



更好的C系列
  1. D C
  2. ,
  3. make.c D


更好的C是一种以一致的方式将现有C项目移植到D的方法。本文分步介绍了将不重要的项目从C转换为D的分步过程,并向您展示了出现的常见问题。



尽管D编译器dmd前端已经转换为D,但它是一个庞大的项目,因此很难完全覆盖它。我需要一个可以完全理解的较小且较谦虚的项目,但这不是一个投机的例子。



我想到了我在1980年代初Datalight C编译器编写的旧的make程序这是经典make程序的真实实现,该程序自1980年代初以来一直在使用。它甚至在标准化之前就用C编写,从一个系统移植到另一个系统,并且仅包含1961行代码,包括注释。今天仍然经常使用。



这是文档源代码make.exe可执行文件的大小为49,692字节,最后修改于2012年8月19日。



我们的邪恶计划:



  1. 最小化C版本和D版本之间的差异。因此,如果程序的行为不同,则更容易找到差异的根源。
  2. 在迁移过程中,不会尝试修复或改进C代码,这是按照第1点进行的。
  3. 不会尝试重构代码。同样,请参见第1点。
  4. 尽可能重现所有错误的C程序的行为。
  5. 为了实现第4段,请做所有必要的事情。


只有完成后,我们才能开始修复,重构,调整等。



剧透!



从C到D的传输完成可执行文件的大小为52,252字节(相比之下,原始文件为49,692字节)。我没有分析大小的增加,但是可能是由于NEWOBJ模板的实例(在C版本中,这是一个宏)以及2012年之后DMC运行时的变化。



一步步



. 664 1961, — , , , , .



#include D: , #include <stdio.h> import core.stdc.stdio;. , Digital Mars C, D ( ). , 29- 64-. (. import).



#if _WIN32 version (Windows). (. ).



extern(C): C. (. ).



debug1, debug2 debug3 debug prinf. , #ifdef DEBUG debug. (. debug).



/* Delete these old C macro definitions...
#ifdef DEBUG
-#define debug1(a)       printf(a)
-#define debug2(a,b)     printf(a,b)
-#define debug3(a,b,c)   printf(a,b,c)
-#else
-#define debug1(a)
-#define debug2(a,b)
-#define debug3(a,b,c)
-#endif
*/

// And replace their usage with the debug statement
// debug2("Returning x%lx\n",datetime);
debug printf("Returning x%lx\n",datetime);


TRUE, FALSE NULL true, false null.



ESC . (. ).



// #define ESC     '!'
enum ESC =      '!';


NEWOBJ .



// #define NEWOBJ(type)    ((type *) mem_calloc(sizeof(type)))
type* NEWOBJ(type)() { return cast(type*) mem_calloc(type.sizeof); }


filenamecmp .



.



D (thread-local storage, TLS). make — , __gshared. (. __gshared).



// int CMDLINELEN;
__gshared int CMDLINELEN


D , typedef . alias. (. alias). , struct.



/*
typedef struct FILENODE
        {       char            *name,genext[EXTMAX+1];
                char            dblcln;
                char            expanding;
                time_t          time;
                filelist        *dep;
                struct RULE     *frule;
                struct FILENODE *next;
        } filenode;
*/
struct FILENODE
{
        char            *name;
        char[EXTMAX1]  genext;
        char            dblcln;
        char            expanding;
        time_t          time;
        filelist        *dep;
        RULE            *frule;
        FILENODE        *next;
}

alias filenode = FILENODE;


D macro — , MACRO.



C, D , :



// char *name,*text;
// In D, the * is part of the type and 
// applies to each symbol in the declaration.
char* name, text;


C D. (. D).



static D . C D, , . __gshared, . (. static).



/*
static ignore_errors = FALSE;
static execute = TRUE;
static gag = FALSE;
static touchem = FALSE;
static debug = FALSE;
static list_lines = FALSE;
static usebuiltin = TRUE;
static print = FALSE;
...
*/

__gshared
{
    bool ignore_errors = false;
    bool execute = true;
    bool gag = false;
    bool touchem = false;
    bool xdebug = false;
    bool list_lines = false;
    bool usebuiltin = true;
    bool print = false;
    ...
}


D . , , , .



make- .



, , , D .



// int cdecl main(int argc,char *argv[])
int main(int argc,char** argv)


mem_init() , .



C , D , .



void cmderr(const char* format, const char* arg) {...}

// cmderr("can't expand response file\n");
cmderr("can't expand response file\n", null);


- (->) C (.), D .



version.



/*
 #if TERMCODE
    ...
 #endif
*/
    version (TERMCODE)
    {
        ...
    }


. D .



// doswitch(p)
// char *p;
void doswitch(char* p)


D debug . xdebug.



C \n\ . D .



/+ +/. (. , ).



static if #if. (. static if).



D , .ptr.



// utime(name,timep);
utime(name,timep.ptr);


const C D, D . (. const immutable).



// linelist **readmakefile(char *makefile,linelist **rl)
linelist **readmakefile(const char *makefile,linelist **rl)


void* char* D .



// buf = mem_realloc(buf,bufmax);
buf = cast(char*)mem_realloc(buf,bufmax);


unsigned uint.



inout , «» . const, , . (. inout-).



// char *skipspace(p) {...}
inout(char) *skipspace(inout(char)* p) {...}


arraysize .length. (. ).



// useCOMMAND  |= inarray(p,builtin,arraysize(builtin));
useCOMMAND  |= inarray(p,builtin.ptr,builtin.length)


(immutable), , . (. ).



// static char envname[] = "@_CMDLINE";
char[10] envname = "@_CMDLINE";


.sizeof sizeof() C. (. .sizeof).



// q = (char *) mem_calloc(sizeof(envname) + len);
q = cast(char *) mem_calloc(envname.sizeof + len)


Windows .



char * void*.



! , . , , — , .



man.c, , make -man. , D, .



make , make-:



\dmd2.079\windows\bin\dmd make.d dman.d -O -release -betterC -I. -I\dmd2.079\src\druntime\import\ shell32.lib




C D, . .



, , :



  • #include import;
  • D- ;
  • ->;
  • :

    • ,
    • ,
    • ,
    • ,
    • ;
  • ;
  • ;
  • ;
  • ;
  • ;
  • C D.


:



  • ,
  • ,
  • ,
  • ,
  • .




, Better C, , :





采取行动



如果您会英语,请前往论坛D并告诉我们您的Better C项目的进展情况!




All Articles