Alibaba Cloud Compiler is a C++ compiler that is developed by Alibaba Cloud based on Clang/LLVM 13, which is an open source community version of Clang/LLVM. Alibaba Cloud Compiler inherits all options and parameters from Clang/LLVM 13, is deeply optimized for Alibaba Cloud infrastructure, and provides additional features to deliver better user experience. This topic describes how to install and use Alibaba Cloud Compiler on Alibaba Cloud Linux 3 to build high-performance C++ applications in a quick manner.
Background information
Compared with GNU Compiler Collection (GCC) and other Clang/LLVM versions, Alibaba Cloud Compiler provides significant improvements in pure compilation and build speed.
Different techniques, such as profile-guided optimization (PGO), are used in Alibaba Cloud Compiler to tune the Clang/LLVM compiler for faster compilation. Alibaba Cloud Compiler builds large-scale C++ code much faster than other compilers, such as GCC.
The Clang/LLVM linker (LLD) outperforms the GNU linker used by GCC, especially in processing large binary files.
Alibaba Cloud Compiler supports C++20 Modules and allows a standard C++ library to be modularized into a std module. Business code can be transformed by using the std module at a low cost to accelerate compilation.
Alibaba Cloud Compiler leverages technologies, such as Alibaba Cloud Compiler (LLVM) ThinLTO, AutoFDO, and CoreBolt, to improve program performance. Alibaba Cloud Compiler can run on different architectures, such as x86 and Arm64, and is tuned for YiTian 710 processors to attain additional performance gains.
Alibaba Cloud Compiler supports Coroutines and Modules and provides modularized standard libraries. Alibaba Cloud provides yaLanTingLibs that includes components commonly used by C++ developers, such as the coroutine library, serialization library, Remote Procedure Call (RPC) library, and HTTP feature.
NoteyaLanTingLibs is a collection of modern C++ utility libraries, including the truct_pack, struct_json, struct_xml, struct_yaml, struct_pb, easylog, coro_rpc, coro_io, coro_http, and async_simple libraries. yaLanTingLibs also includes high-performance, easy-to-use C++ utilities and can help C++ developers build modern, high-performance C++ applications.
Prerequisites
An Elastic Compute Service (ECS) instance that runs Alibaba Cloud Linux 3 is created. For information about how to create an ECS instance, see Create an instance on the Custom Launch tab.
You can use Alibaba Cloud Compiler only on Alibaba Cloud Linux 3.
Install and use Alibaba Cloud Compiler
Connect to the ECS instance on which you want to install Alibaba Cloud Compiler.
For more information, see Connect to a Linux instance by using a password or key.
Run the following command to install Alibaba Cloud Compiler:
sudo yum install -y alibaba-cloud-compiler
Run the following command to import environment variables:
export PATH=/opt/alibaba-cloud-compiler/bin:$PATH
Use Alibaba Cloud Compiler.
Simple compilation example
# The C++ program. cat hello.cpp #include <iostream> int main() { std::cout << "hello C++" << std::endl; return 0; } # Compile the preceding hello.cpp program. clang++ -O2 hello.cpp -o hello.cpp.out
Use C++20 Coroutines and Modules to compile
Alibaba Cloud Compiler supports C++20 Coroutines and Modules, which allow C++ developers to compile in a more efficient manner and improve compilation performance. For information about examples of coroutines, see the Use a standard C++ RPC library and Use a standard C++ HTTP library sections in this topic.
NoteCoroutines are a programming concept that allows you to suspend function execution and then resume the execution at a later time. Traditionally, functions run to completion after the functions are called. Coroutines provide a more flexible control flow mechanism that simplifies asynchronous programming and generator pattern implementation.
In the traditional C++ programming paradigm, code is organized into header files (
.h
/.hpp
) and source files (.cpp
). To use the declarations that are made in a header file in a source file, use the#include
preprocessor directive to insert a copy of the header file into the source file. Compilers may repeatedly parse the same header files due to this convention. As a result, compilation time increases. Modules are introduced as an approach to optimize code organization and increase compilation efficiency.
When you use Clang to compile C++ programs, you can configure parameters. The following table describes the parameters.
Parameter
Description
-std=
Specifies the C++ language standard used for compilation. C++ Coroutines and Modules take effect if you set
-std to c++20
.--precompile
Compiles module units into binary module interface (BMI) files.
-fprebuilt-module-path
Specifies the path in which to search for BMI files.
-fstd-modules
Specifies that files for std modules are compiled.
-fmodules-export-all
Marks all declarations in the current modules as
export
.-fmodules-export-macros
Enables modules to export macros.
-try-load-bmi-when-preprocessing
Searches for BMI files during preprocessing.
-fstd-module-path
Specifies the path in which to search for std modules.
-fcoro-aligned-allocation
Prefers aligned allocation for C++ Coroutines.
Compilation example:
# The Modules code. cat Hello.cppm module; #include <iostream> export module Hello; export void hello() { std::cout << "Hello World!\n"; } cat use.cpp import Hello; int main() { hello(); return 0; } # Compile the preceding sample Modules code. clang++ -std=c++20 Hello.cppm --precompile -o Hello.pcm clang++ -std=c++20 use.cpp -fprebuilt-module-path=. Hello.pcm -o Hello.out ./Hello.out Hello World!
(Optional) Use yaLanTingLibs
You can use yaLanTingLibs, which is a collection of standard C++ libraries that provide the coroutine library, serialization library, RPC library, and HTTP feature based on C++20 Coroutines and the C++ template metaprogramming feature. For more information about yaLanTingLibs, see yalantinglibs and async_simple.
The serialization library is a software library used to serialize and deserialize data. Serialization is the process of converting a data structure or object status into a form that can be stored in files or buffers or transmitted over networks. Deserialization is the process in which data is restructured from its serialized form into the original data structure or object status.
RPC is a library that is used for interprocess communication (IPC). RPC allows C++ programs to execute functions or methods that reside on a remote machine as if the functions or methods were local. RPC abstracts away from details, such as network transmission, serialization, deserialization, and routes, and allows developers to focus on the business logic of their applications.
HTTP is an application-layer protocol for distributed, collaborative, hypermedia information systems. coro_http is a high-performance, easy-to-use HTTP library that uses C++20 Coroutines to implement an HTTP server and client. coro_http can help you quickly develop HTTP applications.
Run the following command to install yaLanTingLibs:
sudo yum install -y yalantinglibs-devel
Use the serialization library, RPC library, and HTTP library of yaLanTingLibs.
Use the serialization library
Create a code file named test.cpp that includes the following code snippet:
#include <iostream> #include "ylt/struct_pack.hpp" struct person { int age; std::string name; }; int main() { person tom{.age=20,.name="tom"}; auto buffer = struct_pack::serialize(tom); auto tom2 = struct_pack::deserialize<person>(buffer); std::cout<<"age: "<<tom2.value().age<<", name: "<<tom2.value().name<<std::endl; return 0; }
The preceding code snippet serializes and deserializes the person data structure.
Run the following command to compile the program:
clang++ test.cpp -std=c++20 -o test
Run the following command to run the program:
./test
The following output is returned:
age: 20, name: tom
Use the RPC library
Create a code file named server.cpp that includes the following code snippet on a server:
#include "ylt/coro_rpc/coro_rpc_server.hpp" std::string ping(std::string ping) { return "Receive: " + ping + ". Return pong."; } int main() { coro_rpc::coro_rpc_server server{1 , 8801}; server.register_handler<ping>(); return server.start(); }
The preceding code snippet starts an RPC server named
coro_rpc
that continuously runs on the server. The RPC server listens to RPC requests on port 8801 and registers theping
function that is used to respond to RPCs.Create a code file named client.cpp that includes the following code snippet on a client:
#include <iostream> #include "ylt/coro_rpc/coro_rpc_client.hpp" std::string ping(std::string); async_simple::coro::Lazy<void> example(){ coro_rpc::coro_rpc_client client; auto ec = co_await client.connect("localhost","8801"); assert(!ec); auto ret = co_await client.call<ping>("ping"); std::cout << ret.value() << std::endl; co_return; }; int main(){ async_simple::coro::syncAwait(example()); return 0; }
The preceding code snippet starts an RPC client that is used to connect to the RPC sever, call the
ping
function, and display the function outputs.Run the following command to compile the server-side program:
clang++ server.cpp -I /usr/include/ylt/thirdparty -std=c++20 -o server -lpthread
Run the following command to compile the client-side program.
NoteBefore you compile the client-side program, make sure that Alibaba Cloud Compiler is installed on the client and environment variables are imported to the client. For more information, see the Install and use Alibaba Cloud Compiler section in this topic.
clang++ client.cpp -I /usr/include/ylt/thirdparty -std=c++20 -o client -lpthread
Run the following command on the server and the client to start the RPC server and client:
./server & ./client
The following log entries are returned by the server-side and client-side programs:
2024-02-02 16:47:11.496 INFO [11960] [coro_rpc_server.hpp:289] begin to listen 2024-02-02 16:47:11.496 INFO [11961] [coro_rpc_client.hpp:412] client_id 0 begin to connect 8801 2024-02-02 16:47:11.496 INFO [11960] [coro_rpc_server.hpp:318] listen port 8801 successfully 2024-02-02 16:47:11.497 INFO [11967] [coro_rpc_server.hpp:348] new client conn_id 1 coming 2024-02-02 16:47:11.497 INFO [11967] [router.hpp:293] route function name: ping Receive: ping. Return pong. 2024-02-02 16:47:11.497 INFO [11968] [coro_rpc_client.hpp:356] client_id 0 close 2024-02-02 16:47:11.497 INFO [11967] [coro_connection.hpp:166] connection 1 close: End of file
The preceding log entries describe the entire process from starting the RPC server, the RPC server listening to RPC requests, the RPC client sending RPC requests, the RPC server processing the RPC requests, to the RPC client closing the connection.
Use the HTTP library
Create a code file named http.cpp that includes the following code snippet:
#include <iostream> #include "ylt/coro_http/coro_http_client.hpp" #include "ylt/coro_http/coro_http_server.hpp" using namespace std::chrono_literals; using namespace coro_http; async_simple::coro::Lazy<void> basic_usage() { coro_http_server server(1, 9001); server.set_http_handler<GET>( "/get", [](coro_http_request &req, coro_http_response &resp) { resp.set_status_and_content(status_type::ok, "ok"); }); server.async_start(); std::this_thread::sleep_for(300ms); coro_http_client client{}; auto result = co_await client.async_get("http://127.0.0.1:9001/get"); assert(result.status == 200); assert(result.resp_body == "ok"); for (auto [key, val] : result.resp_headers) { std::cout << key << ": " << val << "\n"; } } int main() { async_simple::coro::syncAwait(basic_usage()); }
The preceding code snippet starts an HTTP server and registers an HTTP GET service to listen to HTTP requests on port 9001. Then, the code creates an HTTP client to request the HTTP GET service and receive the data returned by the service.
Run the following command to compile the HTTP program:
clang++ http.cpp -I /usr/include/ylt/thirdparty -std=c++20 -o http -lpthread
Run the following command to run the HTTP program:
./http
The following log entries are returned by the program:
2024-02-02 09:07:26.622 INFO [8098] [coro_http_server.hpp:444] begin to listen 2024-02-02 09:07:26.622 INFO [8098] [coro_http_server.hpp:472] listen port 9001 successfully 2024-02-02 09:07:26.923 DEBUG [8101] [coro_http_server.hpp:501] new connection comming, id: 1 Server: cinatra Content-Length: 2 Date: Fri, 02 Feb 2024 01:07:26 GMT 2024-02-02 09:07:26.923 INFO [8103] [coro_http_server.hpp:37] coro_http_server will quit 2024-02-02 09:07:26.923 INFO [8101] [coro_http_server.hpp:491] accept failed, error: Operation aborted. 2024-02-02 09:07:26.923 INFO [8103] [coro_http_server.hpp:112] wait for server's thread-pool finish all work. 2024-02-02 09:07:26.923 INFO [8103] [coro_http_server.hpp:115] server's thread-pool finished. 2024-02-02 09:07:26.923 INFO [8103] [coro_http_server.hpp:117] stop coro_http_server ok