• 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    childProcess.execSync(singleCmd, { windowsHide: true });
123  } catch (e) {
124    // Extract HostTool log information from hilog, which outputs to stdout.
125    let outStream: Buffer = e.stdout;
126    outStream.toString().split(os.EOL).forEach((stdLog: string) => {
127      if (!stdLog.includes(hostToolKeyWords)) {
128        return;
129      }
130      let logHeader: string = '';
131      let logContent: string = '';
132      [logHeader, logContent] = stdLog.split(hostToolKeyWords);
133      if (!logHeader && !logContent) {
134        return;
135      }
136      let logLevel: string = logHeader.trim().split(/\s+/)[logLevelIndex];
137      if (logLevel === 'F' || logLevel === 'E') {
138        logger.warn(`ArkTS:WARN ${logContent}`);
139      }
140    });
141    logger.warn(`ArkTS:WARN ${e}`);
142    logger.warn(`ArkTS:WARN Failed to generate aot file, the module may run with an interpreter`);
143  }
144}
145
146export function generateBuiltinAbc(arkDir: string, abcArgs: string[], cachePath: string,
147  logger: any, faultHandler: FaultHandler, pandaMode: string | undefined): string {
148  const builtinFilePath: string = path.join(getArkBuildDir(arkDir), "aot", "src", "lib_ark_builtins.d.ts");
149  const builtinAbcPath: string = path.join(cachePath, TEMPORARY, "aot", "lib_ark_builtins.d.abc");
150  if (fs.existsSync(builtinAbcPath)) {
151    logger.debug(`builtin.d.abc already exists, no need to rebuild again`);
152    return builtinAbcPath;
153  }
154  mkdirsSync(path.dirname(builtinAbcPath));
155  if (!validateFilePathLengths([builtinFilePath, builtinAbcPath], logger)) {
156    faultHandler(`ArkTS:ERROR generateBuiltinAbc failed. Invalid file path.`);
157  }
158  const tempAbcArgs: string[] = abcArgs.slice(0);
159  let singleCmd: string;
160  if (pandaMode === TS2ABC) {
161    singleCmd= `${tempAbcArgs.join(' ')} "${toUnixPath(builtinFilePath)}" -q -b -m --merge-abc -o "${builtinAbcPath}"`;
162  } else {
163    singleCmd= `${tempAbcArgs.join(' ')} "${toUnixPath(builtinFilePath)}" --type-dts-builtin --type-extractor --module --merge-abc --output "${builtinAbcPath}"`;
164  }
165  try {
166    logger.debug(`generateBuiltinAbc cmd: ${singleCmd}`);
167    childProcess.execSync(singleCmd, { windowsHide: true });
168  } catch (e) {
169    faultHandler(`ArkTS:ERROR Failed to generate builtin to abc. Error message: ${e}`);
170  }
171  return builtinAbcPath;
172}
173