我要评分
获取效率
正确性
完整性
易理解

Consolidating Code of Compiled Languages

After the applications written in compiled language are compiled as executable programs, the instructions vary depending on the processor architecture. Therefore, after software porting, the code in the Kunpeng architecture is different from that in the x86 architecture. During code consolidation, proper measures need to be taken to isolate the code of different architectures. This section uses C/C++ as an example to describe the consolidation methods for code snippets and files.

Using Compilation Macros to Isolate Code Snippets

Compilation macros are used to isolate architecture-specific code at the function level within the same file. You can use the compilation macros provided by the GCC compiler or use customized compilation macros.

Procedure

Example:

The following example shows different implementation methods of CRC instructions on the x86 and Kunpeng platforms. The code in the same file can be distinguished and isolated by compiling macros to implement code consolidation.

  • Compile the following code in the x86 environment:
    #ifdef __x86_64__
    static inline uint32_t crc32_u8(uint32_t crc, uint8_t v) { 
        __asm__("crc32b %1, %0" : "+r"(crc) : "rm"(v)); 
        return crc; 
    } 
    static inline uint32_t crc32_u16(uint32_t crc, uint16_t v) { 
        __asm__("crc32w %1, %0" : "+r"(crc) : "rm"(v)); 
        return crc; 
    } 
    static inline uint32_t crc32_u32(uint32_t crc, uint32_t v) { 
        __asm__("crc32l %1, %0" : "+r"(crc) : "rm"(v)); 
        return crc; 
    } 
    static inline uint32_t crc32_u64(uint32_t crc, uint64_t v) { 
        uint64_t result = crc; 
        __asm__("crc32q %1, %0" : "+r"(result) : "rm"(v)); 
        return result; 
    } 
    #endif
  • Compile the following code in the Kunpeng environment:
    #ifdef __aarch64__
    static inline uint32_t crc32_u8(uint32_t crc, uint8_t value) { 
        __asm__("crc32cb %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)); 
        return crc; 
    } 
    static inline uint32_t crc32_u16(uint32_t crc, uint16_t value) { 
        __asm__("crc32ch %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)); 
        return crc; 
    } 
    static inline uint32_t crc32_u32(uint32_t crc, uint32_t value) { 
        __asm__("crc32cw %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)); 
        return crc; 
    } 
    static inline uint32_t crc32_u64(uint32_t crc, uint64_t value) { 
        __asm__("crc32cx %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(value)); 
        return crc; 
    }
    #endif

In the C and C++ languages, differentiated code block compilation is implemented through conditional compilation using directives such as #ifdef and #endif. In the example, the __x86_64__ macro is used to control the code running on x86, and the __aarch64__ macro is used to control the code running on Arm. The two macros are common macros defined by the GCC. The GCC automatically activates the corresponding macro based on the architecture of the server where the compilation is performed. You do not need to define the macros.

Compilers support user-defined macros, which are passed through the compile command lines and used during code compilation. For example, macros can be customized by adding the -DDEFINES or -DDEFINES=CONDITION parameter for the GCC compiler.

Example of customized macros and code:

#include <stdio.h>
int main(void) {
#ifdef MY_X86_MAC
    printf("Running in x86 model. \n");
#endif
#if MY_AARCH64_MAC
    printf("Running in Kunpeng model. \n");
#endif
    return 0;
}

Save the preceding code to the test.c file. MY_X86_MAC and MY_AARCH64_MAC are user-defined macros that control the x86 code and Kunpeng code, respectively. You can use the GCC compiler to define different macro parameters to implement code for different architectures:

After gcc -DMY_X86_MAC test.c -o demo1 is executed for compilation, the following information is displayed when the demo1 program is run:

Running in x86 model.

After gcc -DMY_AARCH64_MAC test.c -o demo2 is executed for compilation, the following information is displayed when the demo2 program is run:

Running in Kunpeng model.

In this way, both the GCC built-in macros and user-defined macros can be used to isolate code snippets of different architectures in the same file for consolidation.

Using Makefile for Code Consolidation

If a large amount of code of different architectures is involved, the code snippet isolation mode is complex and has drawbacks such as poor readability. You can place the code related to the same architecture in a file, isolate different files, and use Makefile for compilation to implement code consolidation.

Procedure

Place the code of different architectures in different files based on the service code logic, and name and save the files for easy identification. Modify the Makefile to compile the dependency files in their respective architectures to implement code consolidation. The Makefile can be set with multiple phony targets, each dedicated to compiling code files for a specific platform architecture. The caller can initiate the appropriate compilation process simply by executing the make command with the corresponding parameters. Use a script to determine the architecture of the server and automatically complete the compilation and call of the response. Users do not need to determine the platform architecture.

Example:

Assume that src_x86.c and src_aarch64.c store the source code in the x86 architecture and Kunpeng architecture, respectively. The following Makefile example demonstrates how to differentiate and compile the code for each specific platform.

Makefile code snippet for architecture-specific compilation using phony targets:

# other codes
.PHONY x86 aarch64 
x86:src_x86.c     
    gcc  c1.c -o test
arm:src_aarch64.c     
    gcc  src_aarch64.c -o test
# other codes

In this example, running the make x86 command compiles src_x86.c, while running the make aarch64 command compiles src_aarch64.c. The test executable files are generated. This example illustrates the core idea. More source files or options can be added to the actual project.

A script can be used to automatically identify the chip architecture type and execute different compilation commands. The following is a script example:

...
# Obtains the chip type.
ARCH_TYPE=`lscpu | grep Archit | awk '{print $2}'`
echo ${ARCH_TYPE}

# If it is the Kunpeng architecture, run make aarch64.
if [ "$ARCH_TYPE" = "aarch64" ];then
    make aarch64
fi

# If it is the x86 architecture, run make x86.
if [ "$ARCH_TYPE" = "x86_64" ];then
    make x86
fi
...

Save the preceding code to the build.sh file and run the sh build.sh command to complete compilation. Users are unaware of the differences in compiled code corresponding to various chip architectures.

The source code of different architectures is stored in different files. In the Makefile, the compilation methods are differentiated based on the chip type to ensure high code maintainability. It is one of the common methods for adapting the same set of code to multiple platforms.