• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import * as childProcess from 'child_process';
17import * as process from 'process';
18import * as fs from 'fs';
19import * as path from 'path';
20import * as os from 'os';
21import {
22  MODULES_ABC,
23  TEMPORARY,
24  AOT_FULL,
25  AOT_TYPE,
26  AOT_PARTIAL,
27  TS2ABC
28} from './pre_define';
29import {
30  isWindows,
31  mkdirsSync,
32  toUnixPath,
33  validateFilePathLength,
34  validateFilePathLengths
35} from './utils';
36import {
37  getArkBuildDir,
38  getBuildBinDir
39} from './ark_utils';
40
41const hostToolKeyWords: string = '[HostTool] ';
42const logLevelIndex: number = 4;
43
44export interface FaultHandler {
45  (error: string): void
46}
47
48function checkAotPartialConfig(compileMode: string, buildJsonInfo: any, faultHandler: FaultHandler): boolean {
49  if (buildJsonInfo.anBuildMode !== AOT_PARTIAL && !buildJsonInfo.apPath) {
50    // no AOT's partial related configuration is hit, pass the configuration to next compile mode
51    return false;
52  }
53  // Aot compiler's partial mode.
54  return true;
55}
56
57function checkAotFullConfig(compileMode: string, buildJsonInfo: any, faultHandler: FaultHandler): boolean {
58  if (buildJsonInfo.anBuildMode !== AOT_FULL) {
59    // no AOT's full related configuration is hit, pass the configuration to next compile mode
60    return false;
61  }
62  // Aot compiler's full mode.
63  return true;
64}
65
66function checkAotTypeConfig(compileMode: string, buildJsonInfo: any, faultHandler: FaultHandler): boolean {
67  if (buildJsonInfo.anBuildMode !== AOT_TYPE) {
68    // no AOT's type related configuration is hit, pass the configuration to next compile mode
69    return false;
70  }
71  // Aot compiler's type mode.
72  return true;
73}
74
75/**
76 * Check if the AOT related configuration is hit
77 * @param compileMode CompileMode for the project, which can be jsbundle or esmodule
78 * @param buildJsonInfo buildJsonInfo which parsed from projectConfig.aceBuildJson
79 * @param faultHandler faultHandler for illegal AOT configuration
80 * @returns {Boolean} false means no AOT related configuration found, else return true
81 * @api private
82 */
83export function checkAotConfig(compileMode: string, buildJsonInfo: any, faultHandler: FaultHandler): boolean {
84  return checkAotTypeConfig(compileMode, buildJsonInfo, faultHandler) ||
85    checkAotFullConfig(compileMode, buildJsonInfo, faultHandler) ||
86    checkAotPartialConfig(compileMode, buildJsonInfo, faultHandler);
87}
88
89export function generateAot(arkDir: string, builtinAbcPath: string, appAbc: string,
90                            projectConfig: any, logger: any, faultHandler: FaultHandler): void {
91  let aotCompiler: string = path.join(getBuildBinDir(arkDir), isWindows() ? "ark_aot_compiler.exe" : "ark_aot_compiler");
92  const appAot: string = path.join(projectConfig.anBuildOutPut, projectConfig.moduleName);
93
94  if (!validateFilePathLengths([aotCompiler, appAbc, builtinAbcPath, appAot], logger)) {
95    faultHandler(`ArkTS:ERROR generateAot failed. Invalid file path.`);
96  }
97  if (!fs.existsSync(appAbc)) {
98    faultHandler(`ArkTS:ERROR generateAot failed. AppAbc not found in "${appAbc}"`);
99  }
100  const singleCmdPrefix: string = `"${aotCompiler}" --builtins-dts="${builtinAbcPath}" ` +
101    `--aot-file="${appAot}" --compiler-target-triple=aarch64-unknown-linux-gnu `;
102  let singleCmd: string = "";
103  if (projectConfig.anBuildMode === AOT_FULL) {
104    singleCmd = singleCmdPrefix + ` "${appAbc}"`;
105  } else if (projectConfig.anBuildMode === AOT_PARTIAL) {
106    const profile: string = projectConfig.apPath;
107    if (!validateFilePathLength(profile, logger)) {
108      faultHandler(`ArkTS:ERROR generateAot failed. Invalid profile file path.`);
109    }
110    if (!fs.existsSync(profile)) {
111      faultHandler(`ArkTS:ERROR generateAot failed. Partial mode lost profile in "${profile}"`);
112    }
113    singleCmd = singleCmdPrefix + ` --enable-pgo-profiler=true --compiler-pgo-profiler-path="${profile}" "${appAbc}"`;
114  } else {
115    faultHandler(`ArkTS:ERROR generateAot failed. unknown anBuildMode: ${projectConfig.anBuildMode}`);
116  }
117  try {
118    logger.debug(`generateAot cmd: ${singleCmd}`);
119    mkdirsSync(projectConfig.anBuildOutPut);
120    fs.closeSync(fs.openSync(appAot + '.an', 'w'));
121    fs.closeSync(fs.openSync(appAot + '.ai', 'w'));
122  } catch (e) {
123    // Extract HostTool log information from hilog, which outputs to stdout.
124    let outStream: Buffer = e.stdout;
125    outStream.toString().split(os.EOL).forEach((stdLog: string) => {
126      if (!stdLog.includes(hostToolKeyWords)) {
127        return;
128      }
129      let logHeader: string = '';
130      let logContent: string = '';
131      [logHeader, logContent] = stdLog.split(hostToolKeyWords);
132      if (!logHeader && !logContent) {
133        return;
134      }
135      let logLevel: string = logHeader.trim().split(/\s+/)[logLevelIndex];
136      if (logLevel === 'F' || logLevel === 'E') {
137        logger.warn(`ArkTS:WARN ${logContent}`);
138      }
139    });
140    logger.warn(`ArkTS:WARN ${e}`);
141    logger.warn(`ArkTS:WARN Failed to generate aot file, the module may run with an interpreter`);
142  }
143}
144
145export function generateBuiltinAbc(arkDir: string, abcArgs: string[], cachePath: string,
146  logger: any, faultHandler: FaultHandler, pandaMode: string | undefined): string {
147  const builtinFilePath: string = path.join(getArkBuildDir(arkDir), "aot", "src", "lib_ark_builtins.d.ts");
148  const builtinAbcPath: string = path.join(cachePath, TEMPORARY, "aot", "lib_ark_builtins.d.abc");
149  if (fs.existsSync(builtinAbcPath)) {
150    logger.debug(`builtin.d.abc already exists, no need to rebuild again`);
151    return builtinAbcPath;
152  }
153  mkdirsSync(path.dirname(builtinAbcPath));
154  if (!validateFilePathLengths([builtinFilePath, builtinAbcPath], logger)) {
155    faultHandler(`ArkTS:ERROR generateBuiltinAbc failed. Invalid file path.`);
156  }
157  const tempAbcArgs: string[] = abcArgs.slice(0);
158  let singleCmd: string;
159  if (pandaMode === TS2ABC) {
160    singleCmd= `${tempAbcArgs.join(' ')} "${toUnixPath(builtinFilePath)}" -q -b -m --merge-abc -o "${builtinAbcPath}"`;
161  } else {
162    singleCmd= `${tempAbcArgs.join(' ')} "${toUnixPath(builtinFilePath)}" --type-dts-builtin --type-extractor --module --merge-abc --output "${builtinAbcPath}"`;
163  }
164  try {
165    logger.debug(`generateBuiltinAbc cmd: ${singleCmd}`);
166    childProcess.execSync(singleCmd, { windowsHide: true });
167  } catch (e) {
168    faultHandler(`ArkTS:ERROR Failed to generate builtin to abc. Error message: ${e}`);
169  }
170  return builtinAbcPath;
171}
172