添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
高大的板栗  ·  为什么go语言的hello ...·  1 月前    · 
开朗的烈酒  ·  解决ubuntu -bash: cd: ...·  1 年前    · 
说说OpenJDK8中main函数引用的FULL_VERSION在哪定义

说说OpenJDK8中main函数引用的FULL_VERSION在哪定义

引子

刚开始看 openJDK 的源码的时候,准备调试第一个HelloWorld就被难在这里了.
如截图中的这个 FULL_VERSION 是在哪定义的,找了半天也没有找到. 但是调试的时候它就是有值的. 今天就来看看这个值到底是怎么声明的.
大家熟悉的c语言main函数入口


函数定义

先看一下完整的函数定义.

int
main(int argc, char **argv)
    int margc;
    char** margv;
    const jboolean const_javaw = JNI_FALSE;
#endif /* JAVAW */
#ifdef _WIN32
        int i = 0;
        if (getenv(JLDEBUG_ENV_ENTRY) != NULL) {
            printf("Windows original main args:\n");
            for (i = 0 ; i < __argc ; i++) {
                printf("wwwd_args[%d] = %s\n", i, __argv[i]);
    JLI_CmdToArgs(GetCommandLine());
    margc = JLI_GetStdArgc();
    // add one more to mark the end
    margv = (char **)JLI_MemAlloc((margc + 1) * (sizeof(char *)));
        int i = 0;
        StdArg *stdargs = JLI_GetStdArgs();
        for (i = 0 ; i < margc ; i++) {
            margv[i] = stdargs[i].arg;
        margv[i] = NULL;
#else /* *NIXES */
    margc = argc;
    margv = argv;
#endif /* WIN32 */
    return JLI_Launch(margc, margv,
                   sizeof(const_jargs) / sizeof(char *), const_jargs,
                   sizeof(const_appclasspath) / sizeof(char *), const_appclasspath,
                   FULL_VERSION,
                   DOT_VERSION,
                   (const_progname != NULL) ? const_progname : *margv,
                   (const_launcher != NULL) ? const_launcher : *margv,
                   (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE,
                   const_cpwildcard, const_javaw, const_ergo_class);

里面其实有部分是WIN32的相关的代码. 我们把代码精简一下,根据宏定义处理,把不要的内容删除掉:

int
main(int argc, char **argv)
    int margc;
    char** margv;
    const jboolean const_javaw = JNI_FALSE;
    margc = argc;
    margv = argv;
    return JLI_Launch(margc, margv,
                   sizeof(const_jargs) / sizeof(char *), const_jargs,
                   sizeof(const_appclasspath) / sizeof(char *), const_appclasspath,
                   FULL_VERSION,
                   DOT_VERSION,
                   (const_progname != NULL) ? const_progname : *margv,
                   (const_launcher != NULL) ? const_launcher : *margv,
                   (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE,
                   const_cpwildcard, const_javaw, const_ergo_class);

这就是一个标准的c语言的main函数了. 参数argc,argv接入进来. 然后调用方法: JLI_Launch ;

FULL_VERSION 是什么


上面的变量: FULL_VERSION ,实际不是一个变量. 实际是一个宏定义的常量. 只是在全部源代码中没有找到.倒是 DOT_VERSION 有一个宏定义不在上面一点点.代码贴出来如下:

#if defined(JDK_MAJOR_VERSION) && defined(JDK_MINOR_VERSION)
#define DOT_VERSION JDK_MAJOR_VERSION "." JDK_MINOR_VERSION
#else

这个其实就要说到GCC 在编译的时候可以通过命令行传入变量.或者是通过环境变量传入一个预定义的值.比如我写这样的代码:

#include<stdio.h>
int main(int argc ,char** argv)
    printf("%s says: hello world\n",PEOPLE)

然后我编译代码,会报一个错. PEOPLE 没有声明 , 当然还有一个报错是没有分号. (日常犯错)

gcc -g  main.c
main.c: In function ‘main’:
main.c:5: error: ‘PEOPLE’ undeclared (first use in this function)
main.c:5: error: (Each undeclared identifier is reported only once
main.c:5: error: for each function it appears in.)
main.c:6: error: expected ‘;’ before ‘}’ token

加上分号:

#include<stdio.h>
int main(int argc ,char** argv)
    printf("%s says: hello world\n",PEOPLE);

分号好了,仍然有找不到符号的报错:

main.c: In function ‘main’:
main.c:5: error: ‘PEOPLE’ undeclared (first use in this function)
main.c:5: error: (Each undeclared identifier is reported only once
main.c:5: error: for each function it appears in.)

现在有两种处理办法:

  1. 我声明一个宏定义.比如: #define "PEOPLE"
#include<stdio.h>
#define PEOPLE "Jack"
int main(int argc ,char** argv)
    printf("%s says: hello world\n",PEOPLE);

编译运行结果如下:

[root@iZ25a8x4jw7Z ~/ccode/define]#gcc -g  main.c
[root@iZ25a8x4jw7Z ~/ccode/define]#./a.out
Jack says: hello world

但是,如果程序里面真的没有声明,或者我想在编译的时候再动态给怎么办呢?

  1. 在编译参数中动态声明:
[root@iZ25a8x4jw7Z ~/ccode/define]#gcc -g  -DPEOPLE=\"JackMa\"  main.c
[root@iZ25a8x4jw7Z ~/ccode/define]#./a.out
JackMa says: hello world

因此,在此OpenJDK的代码中,应该也是这样定义的. 但是事情并没有我们想象的那么简单.
如果真的这么简单这就是不JDK源代码了. 搜索源代码全文路径里面. 有如下一段代码:


这里其实省略了很多中间过程, 如果你很了解GNUMAKE的话. 那应该能像我现在一样能够直接得到这个结果.而把其它干扰的结果全部给排除掉.

上图中的两个框分别有两个 FULL_VERSION= 这样的赋值操作.仔细分别看两段代码:

speck.gmk 中的定义如下:
ifneq ($(USER_RELEASE_SUFFIX), )
  FULL_VERSION=$(RELEASE)-$(USER_RELEASE_SUFFIX)-$(JDK_BUILD_NUMBER)
  FULL_VERSION=$(RELEASE)-$(JDK_BUILD_NUMBER)
endif
JRE_RELEASE_VERSION:=$(FULL_VERSION)
speck.gmk.in 中的定义如下:
ifneq ($(USER_RELEASE_SUFFIX), )