说说OpenJDK8中main函数引用的FULL_VERSION在哪定义
引子
刚开始看openJDK
的源码的时候,准备调试第一个HelloWorld就被难在这里了.
如截图中的这个FULL_VERSION
是在哪定义的,找了半天也没有找到. 但是调试的时候它就是有值的. 今天就来看看这个值到底是怎么声明的.
函数定义
先看一下完整的函数定义.
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.)
现在有两种处理办法:
-
我声明一个宏定义.比如:
#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
但是,如果程序里面真的没有声明,或者我想在编译的时候再动态给怎么办呢?
- 在编译参数中动态声明:
[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), )