为什么这篇文章要把 C 语言和 ABAP 放在一起讲,而不是别的语言比方 Java 和 ABAP 呢?因为 ABAP 语言底层是基于 C/C++ 实现的,包含其关键字 (比方最简略的关键字 WRITE 的 C++ 实现有 2 千多行) 和虚拟机(ABAP Runtime)。SAP 外部的一群计算机科学家们创造了 ABAP 这门平凡的语言,由它实现的各种 SAP 利用帮忙了寰球超过 180 个国家和地区的客户们更好地运行其业务。
通过 Google 咱们能搜寻到一些对于这些 SAP 计算机科学家们的介绍,比方这个链接:
比方像下图这种用 kernel module
润饰的 sc_km_check_feature_2, 以及每一个 ABAP 关键字,其 C 语言的实现代码在 SAP 外部的 Netweaver 零碎能够查看到,然而在客户零碎上,则是以二进制指标文件的模式存储,无奈查看源代码。
本文的目标是心愿通过 C 语言和 ABAP 编译过程的一些介绍,加深 ABAP 参谋们对这门语言的了解。
用 C 语言写个 Hello World 程序,另存为 study.c:
用命令行 gcc ./study.c --verbose
进行编译,参数 verbose 可供咱们查看编译明细。上述命令行在我的 Ubuntu 零碎上产生一串长长的输入:
咱们能够一步步剖析。首先用参数 - E 查看预处理生成的指标文件 study.i:
gcc -E study.c -o study.i
能够看到源代码文件只有 78
字节,编译预处理后生成的输入文件有 17116
字节。
为什么收缩了这么多?起因是因为我源代码文件的第一行,#include<stdio.h>
被预处理器替换成了 stdio.h
的理论内容,而 stdio.h 里如果又存在 #include
其余文件的申明,这个替换过程会递归执行。因而直到 study.i 的开端局部,咱们能力看到在 study.c 里书写的源代码局部。
源代码文件 study.c 里的第一行语句 #include<stdio.h>
, 请大家记住,前面讲 ABAP 还会提到。
用命令行 gcc -S 能够查看 study.c 编译后生成的汇编代码:
看到这些 pushq, popq, %rbp
,Jerry 不由得想起本科汇编程序设计专业课上,我和寝室其余兄弟坐在教室最初一排看体坛周报的时光。
工作十多年后,Jerry 不得不抵赖,过后本科开设的计算机专业课,像数据结构,操作系统,计算机组成原理,编译原理,汇编程序设计,计算机图形学这些都是有用的,工作后,公司不可能再给你工夫去学习这些基础理论常识了。
尽管汇编程序设计这门课 Jerry 当初没有好好学,但至多教材我是妥善保留了的,以防哪天公司的工作安顿须要让我把十多年前在学校学的货色从新又捡起来。
上面咱们来聊聊 ABAP。
SAP note 1230076 Generation of ABAP loads: Tips for the analysis
介绍了一个工具程序:RSDEPEND. 这个 note 提到,一个即使看起来最简略的 ABAP Hello World 报表,其实也依赖于许多规范的 Repository 对象,这些依赖咱们假设称其为 A,B,C。假如 A,B,C 其中有任何一个有改变产生,比方 A 是一个 include 程序,外面应用到了一个 DDIC 构造,在某个时刻,零碎导入了一个传输申请 (Transport Request), 外面蕴含了针对这个 DDIC 构造的更改,那么此时这个最简略的 Hello World 报表的 load 就成为了 obsolete 状态。在从新执行该报表之前,ABAP Runtime(中文译成 ABAP 运行时
) 会主动做一个 load invalidation 操作,生成一个最新版本的 load.
什么是 ABAP load?看 ABAP help 里的官网定义:
In the ABAP environment, a load describes a binary representation of a repository object which is optimized for fast access, in the memory or on the database.
翻译成中文:ABAP load 是 Repository 对象的二进制表现形式,针对 ABAP 环境的快速访问而做过特地优化,能够存储在数据库表中或者加载于内存里。
咱们用一个理论的例子来了解 ABAP 报表激活和运行时产生的事件。
创立一张非常简单的通明表 ZLOADTEST:
写一个简略的报表,命名为 ZTESTLOAD. 报表的源代码以压缩的格局存储在表 REPOSRC 的 DATA 字段里。
测试报表的源代码很简略,把表里的数据全副读取进去:
激活这个简略的报表(是的,在 ABAP 世界里,咱们习惯说激活,而不是编译)。激活后生成的 ABAP load 存储在表 REPOLOAD 的字段 LDATA 和 QDATA 里。
这两个字段存储的内容就是后面 ABAP help 提到的 ABAP load 在数据库表中的存储模式。
菜单 Goto->Navigate to->Switch to Classic Debugger
:
Goto->System Areas->Internal Information
:
在 System Area 区域输出 CONT,就能在下图的 NAME 列看到 ABAP load 里蕴含的指令。当然同开源的 JVM 不同,JVM 字节码指令集在网上可能查到,而这些 ABAP load 的指令是 SAP internal 的,因而不能在这里做解释。
而后执行后面提到的工具报表 RSDEPEND, 输出参数 program name = ZTESTLOAD
, 失去后果,其中测试报表的 ABAP Load 工夫戳为 07:21:02, 这个报表依赖的规范 Include 有:
- <REPINI>
- <SYSINI>
- <SYSSEL>
- DB__SSEL
由此看出,每一个规范的 ABAP 报表都主动蕴含了这些 include. 如果开发人员显式地再蕴含其中任意一个,会遇到语法错误:
Module %_PF_STATUS is already defined as a OUTPUT module
大家感觉这个 <REPINI>
是不是很像前文 C 语言局部提到的 #include<stdio.h>
?
上面咱们再做几轮测试。
测试 1
批改通明表的形容信息,而后从新激活通明表。
执行 RSDEPEND, 能够看到只有通明表的 Last Changed 字段产生了变动,ABAP Time Stamp 和 Screen Time Stamp 都不变,这是咱们冀望的后果,因为咱们只是批改了通明表的形容信息,并未批改构造。
再次执行测试报表 ZTESTLOAD, 用 RSDEPEND 检测,发现测试报表的 ABAP Load 工夫戳没有发生变化,这阐明:即便依赖的通明表的形容信息发生变化,应用了该通明表的 ABAP 报表不须要从新编译,因为通明表形容信息不须要在报表执行期应用。
测试 2
给通明表减少新的一列,再次激活。
此时通过 RSDEPEND 发现,通明表的三个工夫戳全副产生了变动,如下图蓝色矩形框所示。然而测试报表 ABAP Load 自身的工夫戳依然未变,这也是正当的,因为咱们给通明表里减少了新的列后,还未执行测试报表。
再次执行 ZTESTLOAD 后,这次发现它的 ABAP Load 曾经被主动 invalidate 了,工夫戳从 07:21:02 变成了 07:36:02。
这也解释了一个景象:有的敌人们察看到,当零碎刚升完级后,或者有一批新的传输申请导入到零碎后,第一次应用 SAP 利用时,零碎响应速度很慢。起因其实通过前文的两个测试曾经阐明了:零碎在破费工夫去做相干 ABAP Load invalidation. 在利用依赖的这些 Load invalidation 没有完结之前,零碎无奈响应用户申请。
为了防止用户在第一次应用利用时长时间期待,能够应用事务码 SGEN 事后进行 Load invalidation. SGEN 具体的应用办法能够参考上面这篇文章
心愿这篇文章能给那些想理解 ABAP 语言底层一些实现细节的参谋敌人们有所帮忙。
总结
ABAP 是基于 Netweaver 技术栈的 SAP 产品比方 CRM,S/4HANA 等的业务逻辑和底层零碎平台实现采取的编程语言。ABAP 是一门高级面向对象的编程语言,其运行时和内核基于 C/C++ 实现。本文通过一些具体的 ABAP 报表例子,介绍了 ABAP 语言的一些底层实现细节。