This skill should be used when the user asks to "分析构建错误", "analyze build errors", "查看编译错误", "检查构建日志", "诊断链接错误", "fix build errors", "resolve compilation errors", "分析 last_error.log", "extract build error", "分析SDK的编译错误", "分析 SDK 编译错误", "analyze SDK build errors", "check SDK errors", "诊断 sdk 编译错误", or mentions analyzing build failures, compilation errors, linker errors, undefined symbols, SDK compilation errors, or needs to fix build issues. Focuses on reading last_error.log from out/<product>/ directory (or out/sdk/ for SDK builds) and providing specific fix recommendations based on error patterns and historical cases.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
This skill should be used when the user asks to "分析构建错误", "analyze build errors", "查看编译错误", "检查构建日志", "诊断链接错误", "fix build errors", "resolve compilation errors", "分析 last_error.log", "extract build error", "分析SDK的编译错误", "分析 SDK 编译错误", "analyze SDK build errors", "check SDK errors", "诊断 sdk 编译错误", or mentions analyzing build failures, compilation errors, linker errors, undefined symbols, SDK compilation errors, or needs to fix build issues. Focuses on reading last_error.log from out/<product>/ directory (or out/sdk/ for SDK builds) and providing specific fix recommendations based on error patterns and historical cases.
version
0.9.0
Build Error Analyzer Skill
This skill specializes in analyzing OpenHarmony build errors from last_error.log and providing fix recommendations only (no automatic code modifications) based on error patterns and historical case studies.
IMPORTANT: This skill provides analysis and recommendations ONLY. It does NOT automatically modify code files.
⚠️ CRITICAL WORKFLOW (MUST FOLLOW)
YOU MUST ALWAYS FOLLOW THIS EXACT SEQUENCE:
FIRST: Extract errors from out/<product>/build.log → generates out/<product>/last_error.log
THEN: Read and analyze ONLY from out/<product>/last_error.log
NEVER: Read directly from out/<product>/build.log or any other log files (error.log, build_output*.log, etc.)
SUCCESS CASE: If last_error.log contains "build success" or "no error", STOP and report success
Why?:
build.log contains the entire build history (thousands of lines)
last_error.log contains ONLY the most recent error block (extracted by script)
Reading build.log directly will give you STALE or IRRELEVANT errors
The extraction script ensures you always analyze the LATEST errors
Other log files (error.log, build_output*.log) may contain outdated errors from previous builds
Before reading ANY errors, ALWAYS run:
# ⚠️ CRITICAL: First cd to OpenHarmony root directory, then run the scriptcd <openharmony_root>
foundation/arkui/ace_engine/.claude/skills/build-error-analyzer/script/extract_last_error.sh out/<product>/build.log
⚠️ CRITICAL - CHECK FOR SUCCESS FIRST:
After reading last_error.log, if you see:
✅ Extract errors from out/<product>/build.log using the script → creates out/<product>/last_error.log
✅ For SDK: Extract from out/sdk/build.log → creates out/sdk/last_error.log
✅ Analyze errors from the extracted last_error.log ONLY
✅ Provide fix recommendations ONLY - do NOT modify code
Common Mistakes to Avoid:
❌ Reading build.log directly (will get stale/wrong errors)
❌ Reading error.log (contains outdated errors from previous builds)
❌ Reading other log files (build_output*.log, error.*.log, etc.)
❌ Continuing to search for errors when last_error.log shows "build success"
❌ Analyzing errors without extraction step
❌ Running extraction script from wrong directory (MUST be from OpenHarmony root)
✅ ALWAYS cd to <openharmony_root> first
✅ ALWAYS extract → then read last_error.log ONLY
✅ If last_error.log shows success → STOP and report success
Behavior Guidelines
This skill provides ANALYSIS and RECOMMENDATIONS ONLY:
✅ DO:
Extract errors from build logs
Analyze and categorize errors
Match errors against known patterns
Provide detailed fix recommendations with file paths and line numbers
Show before/after code examples
Explain root causes
Suggest verification steps
❌ DO NOT:
Use Edit tool to modify code files
Use Write tool to create or modify files
Run build commands automatically
Apply fixes without user confirmation
Make any changes to the codebase
Read from log files other than last_error.log (error.log, build_output*.log, error.*.log, etc.)
Continue searching for errors when build is successful
⚠️ CRITICAL - NEVER SUGGEST CLEARING LTO CACHE:
❌ NEVER suggest clearing thinlto-cache directory
❌ NEVER suggest clearing llvmcache-* directories
❌ NEVER suggest deleting out/obj directory
❌ NEVER suggest deleting entire out/ directory
❌ NEVER blame LTO cache for build errors
❌ NEVER suggest "clean build" as first solution
Why: The user should review and apply fixes manually to maintain control over code changes and understand the modifications. LTO cache issues are extremely rare and clearing caches as first resort masks real problems, wastes rebuild time, and disrupts incremental compilation benefits.
Prerequisites
⚠️ CRITICAL: ALWAYS extract from out/<product>/build.log FIRST before reading
Error log location: The skill reads errors ONLY from out/<product>/last_error.log (same directory as build.log)
Error extraction: ALWAYS use the extraction script from foundation/arkui/ace_engine/.claude/skills/build-error-analyzer/script/extract_last_error.sh (from OpenHarmony root) to generate/update last_error.log before reading
Source build.log: Errors are extracted ONLY from out/<product>/build.log in the OpenHarmony output directory
Codebase context: Can be executed from any OpenHarmony directory (ace_engine, root, etc.)
⚠️ SUCCESS CHECK: If last_error.log contains "build success" or "no error", STOP and report success - DO NOT read other log files like error.log, build_output*.log, etc.
EXCLUSIVE LOG SOURCE: ONLY read from last_error.log - NEVER from error.log, build_output*.log, error.*.log, or any other log files
Analysis Workflow
Step 1: Extract Latest Error (REQUIRED - ALWAYS DO THIS FIRST)
⚠️ CRITICAL: This step is MANDATORY and must be done BEFORE reading any errors.
Why this is required:
build.log contains the full build output (old and new errors mixed together)
Reading it directly will analyze STALE or IRRELEVANT errors
The extraction script isolates ONLY the most recent error block
last_error.log is generated in the same directory as build.log
⚠️ IMPORTANT: Always navigate to OpenHarmony root first, then run the script:
# Step 1: Navigate to OpenHarmony root directorycd <openharmony_root>
# Step 2: Run the extraction script (relative path from root)# Example for rk3568 product - extract errors from out/rk3568/build.log
foundation/arkui/ace_engine/.claude/skills/build-error-analyzer/script/extract_last_error.sh out/rk3568/build.log
# Example for SDK product - extract errors from out/sdk/build.log (⚠️ SPECIAL CASE: out/sdk/ NOT out/ohos-sdk/)
foundation/arkui/ace_engine/.claude/skills/build-error-analyzer/script/extract_last_error.sh out/sdk/build.log
# Example for other products:
foundation/arkui/ace_engine/.claude/skills/build-error-analyzer/script/extract_last_error.sh out/rk3588/build.log
The script will:
Extract ONLY the latest error block from out/<product>/build.log
Output to out/<product>/last_error.log (same directory)
Show error block size and summary
Overwrite previous last_error.log if it exists
⚠️ DO NOT SKIP THIS STEP
Even if last_error.log exists, RE-EXTRACT to get the latest errors
DO NOT read build.log directly
DO NOT read other log files (build_output*.log, error.log, error.*.log, etc.)
ONLY analyze last_error.log after extraction
Step 2: Read and Categorize Errors
⚠️ CRITICAL: Only read last_error.log from out/<product>/ directory in the OpenHarmony output tree.
After extraction, the error log is located at:
out/<product>/last_error.log (same directory as build.log)
Read the extracted error log:
# Check for last_error.log in common product directoriescat out/rk3568/last_error.log
# or for SDK (⚠️ SPECIAL CASE: out/sdk/ NOT out/ohos-sdk/)cat out/sdk/last_error.log
# or for other productscat out/rk3588/last_error.log
⚠️ CRITICAL - CHECK FOR SUCCESS FIRST:
Before any analysis, CHECK if the build succeeded:
**DO NOT**:
- ❌ Use Edit tool to make changes
- ❌ Use Write tool to create/modify files
- ❌ Run build commands automatically
**DO**:
- ✅ Provide clear recommendations with file paths and line numbers
- ✅ Show before/after code snippets
- ✅ Explain why the fix works
- ✅ Suggest verification commands
## Error Patterns and Solutions
### Pattern 1: Undefined Symbol Errors
**Error signature:**
ld.lld: error: undefined symbol: <symbol_name>
referenced by :
**⚠️ CRITICAL ANALYSIS WORKFLOW (MUST FOLLOW IN ORDER):**
When encountering `ld.lld: error: undefined symbol:` linker errors, you MUST follow this sequence:
#### Step 1: Identify Which Library is Failing to Link
Check the error message to determine which library has the undefined symbol:
- Look for the target being built (e.g., `libace.z.so`, `libace_compatible.z.so`, `libarkoala_native_ani.so`, `libace_ndk.z.so`)
- Check which library is referencing the symbol (`>>> referenced by`)
#### Step 2: Apply the Correct Scenario Based on Library Type
**Scenario 1: libace/libace_compatible Main Library Cannot Find Symbol**
**Symptoms:**
- Error occurs when linking `libace.z.so` or `libace_compatible.z.so`
- Symbol is undefined in the main library itself
**Root Cause:**
- Symbol implementation is missing or not compiled
- Method exists but .cpp file not in BUILD.gn
**Solution:**
1. **Check if implementation exists:**
```bash
grep -r "SymbolName" --include="*.cpp" frameworks/
Find where other files in same directory are added
Add the missing .cpp to the appropriate source_set
Important: Reference files in same directory to find correct source_set
DO NOT assume all files go to ace_core_ng_source_set
Verify with other files:
# Find where similar files in same directory are compiled
find frameworks/core/components_ng/pattern/<pattern_name>/ -name "*.cpp"
grep "similar_file.cpp" frameworks/core/BUILD.gn
Scenario 2: Other Library Links with libace/libace_compatible Dependency
Symptoms:
Error occurs when linking a library that depends on libace or libace_compatible
GN file shows deps includes libace/libace_compatible
Symbol should come from main library
Root Cause:
Symbol exists in main library but not exported
Missing ACE_FORCE_EXPORT macro
Symbol not in libace.map whitelist
⚠️ CRITICAL: Distinguish Non-Template vs Template FIRST
Before applying any solution, determine the type:
undefined symbol error
↓
Is it a non-template class method?
→ YES: Use Non-Template Solution (Step 1A)
→ NO: Use Template Solution (Step 1B, see Scenario 3)
Solution (Step-by-Step):
Step 1A: For NON-TEMPLATE class methods ⭐
⚠️ CHECK 1: Does the class have ACE_FORCE_EXPORT?
// Case A: Class WITHOUT ACE_FORCE_EXPORTclassPaddingPropertyF {
floatWidth()const;
};
// Case B: Class WITH ACE_FORCE_EXPORTclassACE_FORCE_EXPORT PaddingPropertyF {
floatWidth()const;
};
For Case A (Class WITHOUT export) - PREFERRED METHOD:
✅ Add ACE_FORCE_EXPORT to method declaration in header (.h file)
❌ DO NOT add to method definition in .cpp file
Reason: Fine-grained export control, clear API boundaries
Example (PaddingPropertyF case):
// In header file (.h) - Add ACE_FORCE_EXPORT to method declarationsclassPaddingPropertyF {
ACE_FORCE_EXPORT floatWidth()const; // ← Add hereACE_FORCE_EXPORT floatHeight()const; // ← Add here
};
// In implementation file (.cpp) - NO ACE_FORCE_EXPORT herefloatPaddingPropertyF::Width()const{
return left.value_or(0.0f) + right.value_or(0.0f);
}
floatPaddingPropertyF::Height()const{
return top.value_or(0.0f) + bottom.value_or(0.0f);
}
For Case B (Class WITH export):
✅ NO additional export needed - class export covers all methods
❌ DO NOT add ACE_FORCE_EXPORT to individual methods
Reason: Entire class already exported
Example:
// In header file (.h) - Class already exportedclassACE_FORCE_EXPORT PaddingPropertyF { // ← Entire class exportedfloatWidth()const; // Automatically exportedfloatHeight()const; // Automatically exported
};
// In implementation file (.cpp) - No individual exports neededfloatPaddingPropertyF::Width()const{ /* implementation */ }
Step 1B: For TEMPLATE class methods/functions (see Scenario 3)
Template-specific rules apply - refer to Scenario 3 for detailed steps.
Step 2: Add to libace.map with fine-grained symbol names ⭐
After adding exports, add the symbol to build/libace.map:
# Check if symbol already in libace.map
grep "ClassName" build/libace.map
Required changes:
⭐ ALWAYS prefer fine-grained symbol patterns - Export specific methods over entire class
Add symbol pattern to build/libace.map whitelist
Use method-level granularity when possible
Example - Regular Methods:
# In build/libace.map
{
global:
# ✅ FINE-GRAINED - Export specific methods (PREFERRED for non-template)
OHOS::Ace::PaddingPropertyF::Width*;
OHOS::Ace::PaddingPropertyF::Height*;
# ⚠️ ACCEPTABLE - Export entire class (if class has ACE_FORCE_EXPORT)
OHOS::Ace::PaddingPropertyF::*;
# ⚠️ DIFFERENT - Template patterns (use wildcards)
void?OHOS::Ace::StringUtils::StringSplitter*; # Template function
OHOS::Ace::NG::LayoutConstraintT*; # Template class
};
}
Why fine-grained for non-templates?
⭐ Minimizes exported symbol surface - Only export what's needed
⭐ Clearer API boundaries - Explicit about which symbols are public
Rebuild after adding ACE_FORCE_EXPORT and libace.map entry
Common mistakes (DO NOT do):
❌ DO NOT use ClassName::*; when only specific methods are needed (⚠️ COMMON MISTAKE)
❌ DO NOT export all class members when only constructors are undefined
❌ DO NOT mix non-template and template rules
❌ DO NOT add export to .cpp for non-template methods
❌ DO NOT add individual method exports if class already has ACE_FORCE_EXPORT
❌ DO NOT use __attribute__((visibility("default"))) directly
⚠️ Example of Common Mistake - Over-Exporting:
// ❌ WRONG - Exports entire class when only constructors needed
OHOS::Ace::VelocityTracker::*; // Exports ALL members unnecessarily// ✅ CORRECT - Fine-grained constructor export
OHOS::Ace::VelocityTracker::VelocityTracker*; // Only constructors
When to use each pattern:
Use ClassName::MethodName*; for specific methods
Use ClassName::ClassName*; for all constructor overloads
Use ClassName::*; ONLY when most/all members are exported (rare)
Scenario 3: Template Function Instantiation Issues
Symptoms:
Undefined symbol is a template function
Template uses forward declaration + explicit instantiation in .cpp
Error shows missing specific template specialization (e.g., StringSplitter<Color>, TransformStrCase<std::string>)
Root Cause:
New specialization not explicitly instantiated
Template declaration or implementation missing export macro
libace.map missing pattern for template instantiation
Solution (3 steps required):
Step 1: Add extern template declaration in header (.h)
Add explicit template declaration for new specialization:
// In header file (.h)externtemplatevoidStringSplitter<Color>(const std::string& source, char delimiter,
Color (*)(const std::string&), std::vector<Color>& out);
Step 2: Add ACE_FORCE_EXPORT to template function declaration
// In header file (.h) - Template function declarationtemplate<class T>
ACE_FORCE_EXPORT
voidStringSplitter(
const std::string& source, char delimiter, T (*func)(const std::string&), std::vector<T>& out);
Step 3: Add explicit instantiation in .cpp
// In implementation file (.cpp)templatevoidStringSplitter<Color>(const std::string& source, char delimiter,
Color (*)(const std::string&), std::vector<Color>& out);
Step 4: Add ACE_FORCE_EXPORT to template implementation
// In implementation file (.cpp) - Template function implementationtemplate<class T>
ACE_FORCE_EXPORT
voidStringSplitter(
const std::string& source, char delimiter, T (*func)(const std::string&), std::vector<T>& out){
// implementation
}
Step 5: Add to libace.map whitelist
# In build/libace.map
{
global:
OHOS::Ace::StringUtils::*;
void?OHOS::Ace::StringUtils::StringSplitter*; # Match template instantiations
void?OHOS::Ace::StringUtils::TransformStrCase*; # Match template instantiations
};
⚠️ Template Special Notes:
Templates require BOTH declaration and implementation to have export macros
Explicit instantiation must be in .cpp file
libace.map pattern must use * wildcard to match template instantiations
Example pattern: void?OHOS::Ace::StringUtils::StringSplitter*;
Scenario 4: Special Libraries (Rare Cases)
Symptoms:
Library does NOT depend on libace/libace_compatible
But uses utility functions from main library (previously inline, now in .cpp)
Only applies to these specific libraries:
libarkoala_native_ani.so
libace_ndk.z.so
Root Cause:
Utility functions changed from inline to .cpp implementation
Symbol not available because library doesn't link main library
Special case requiring local compilation
Solution:
Add the utility .cpp file directly to the library's BUILD.gn sources
Each method implementation that needs to be exported must have the macro
Solution:
Step 1: Add ACE_FORCE_EXPORT to method implementation in .cpp
Add ACE_FORCE_EXPORT to each template method implementation that needs to be exported:
// In implementation file (.cpp)template<typename T>
ACE_FORCE_EXPORT // ← Add this macro before return typebool LayoutConstraintT<T>::UpdateSelfMarginSizeWithCheck(const OptionalSize<T>& size)
{
if (selfIdealSize == size) {
returnfalse;
}
return selfIdealSize.UpdateSizeWithCheck(size);
}
template<typename T>
ACE_FORCE_EXPORT // ← Add this macro before return typebool LayoutConstraintT<T>::UpdateMaxSizeWithCheck(const SizeT<T>& size)
{
if (maxSize == size) {
returnfalse;
}
return maxSize.UpdateSizeWhenSmaller(size);
}
⚠️ Template Method Export Notes:
Struct declaration export is NOT enough: Having struct ACE_FORCE_EXPORT LayoutConstraintT doesn't automatically export all methods
Each method needs macro: Every method implementation in .cpp that must be exported needs ACE_FORCE_EXPORT
Place macro before return type: The macro goes between template<> and return type
Not needed in header: Don't add ACE_FORCE_EXPORT to method declarations in header file (struct declaration is sufficient)
Step 2: Verify libace.map has wildcard pattern
Check that libace.map includes the template class with wildcard:
# Check libace.map for template class pattern
grep "LayoutConstraintT" build/libace.map
Expected output:
OHOS::Ace::NG::LayoutConstraintT*;
⚠️ libace.map Wildcard Rules:
Use unquoted patterns with wildcards: OHOS::Ace::ClassName::*;
DO NOT use quoted patterns with wildcards: "OHOS::Ace::ClassName<T>::*;" (wildcards won't work)
Unquoted wildcards match all template instantiations automatically
Use * at end to match all methods: OHOS::Ace::NG::LayoutConstraintT*;
Step 3: Verify symbol export
# Check if symbol is exported in shared library
nm -D out/rk3568/arkui/ace_engine/libace.z.so | grep LayoutConstraintT
Expected output (should show exported symbols):
0000000000000000 T _ZN2OHOS3Ace2NG14LayoutConstraintTIfE25UpdateSelfMarginSizeWithCheckERKNS0_11OptionalSizeIfEE
⚠️ Common Mistakes:
❌ Relying only on struct ACE_FORCE_EXPORT ClassName - NOT sufficient for methods
❌ Forgetting to add macro to each method implementation in .cpp
❌ Adding macro to method declarations in header (unnecessary, struct declaration is enough)
❌ Using quoted patterns in libace.map: "ClassName<T>::*" won't match
❌ Adding specific template instantiations to libace.map: use wildcards instead
✅ Correct Approach:
✅ Add ACE_FORCE_EXPORT to each template method implementation in .cpp
✅ Place macro between template<> and return type
✅ Keep struct declaration with ACE_FORCE_EXPORT in header
✅ Use unquoted wildcard in libace.map: OHOS::Ace::NG::ClassName*;
Step 3: Verify the Fix
After applying the appropriate solution:
# 1. Navigate to OpenHarmony root and rebuildcd <openharmony_root>
./build.sh --product-name rk3568 --build-target ace_engine
# 2. Check if symbol is now exported (for scenarios 2-3)
nm -D out/rk3568/arkui/ace_engine/libace.z.so | grep SymbolName
# 3. Extract new errors
foundation/arkui/ace_engine/.claude/skills/build-error-analyzer/script/extract_last_error.sh out/rk3568/build.log
# 4. Check resultcat out/rk3568/last_error.log
# For SDK builds (⚠️ use out/sdk/ directory):# 1. Build SDK: ./build.sh --product-name ohos-sdk --ccache# 2. Extract errors: foundation/arkui/ace_engine/.claude/skills/build-error-analyzer/script/extract_last_error.sh out/sdk/build.log# 3. Check result: cat out/sdk/last_error.log
Common mistakes (DO NOT do):
⚠️ CRITICAL - CACHE CLEARING IS FORBIDDEN:
❌ NEVER suggest clearing thinlto-cache (99.9% of the time it's NOT the issue)
❌ NEVER suggest clearing llvmcache-* directories
❌ NEVER suggest deleting out/obj directory
❌ NEVER suggest deleting entire out directory
❌ NEVER suggest "clean build" as first solution
❌ Cache clearing masks real problems and wastes massive rebuild time
✅ ALWAYS analyze the actual error and fix the root cause
Other common mistakes:
❌ DO NOT skip scenario analysis
❌ DO NOT use __attribute__((visibility("default"))) instead of ACE_FORCE_EXPORT
❌ DO NOT forget both declaration AND implementation export for templates
❌ DO NOT use Scenario 4 (local compilation) except for the two specified libraries
❌ DO NOT rely only on struct ACE_FORCE_EXPORT ClassName for template class methods (Scenario 5)
❌ DO NOT use quoted patterns with wildcards in libace.map: "ClassName<T>::*" doesn't work (Scenario 5)
✅ ALWAYS do:
✅ Identify which library is failing
✅ Check if implementation exists and is compiled
✅ Verify ACE_FORCE_EXPORT on header declarations
✅ Check libace.map whitelist
✅ For templates: check declaration, implementation, and instantiation
✅ Use correct scenario based on library type
✅ For template class methods: add ACE_FORCE_EXPORT to each method implementation in .cpp (Scenario 5)
✅ Use unquoted wildcard patterns in libace.map: OHOS::Ace::NG::ClassName*; (Scenario 5)
Pattern 2: Incomplete Type Errors
Error signature:
error: member access into incomplete type 'const ClassName'
error: invalid use of incomplete type 'class ClassName'
error: member access into incomplete type 'OHOS::Ace::Animator'
rawPtr_->IncRefCount();
Common causes:
Missing header include
Forward declaration without full definition
RefPtr as class member without proper implementation separation
Header file optimization issues
⚠️ SPECIAL CASE: RefPtr as Class Member
When encountering incomplete type errors with RefPtr<T> or WeakPtr<T> as class members:
DO NOT simply add the full include to the header file. Instead:
Keep forward declaration in header: class Animator;
Declare special member functions in header (without = default):
AnimatableColor(); // Declaration only
~AnimatableColor(); // Declaration onlyAnimatableColor(const AnimatableColor& color); // Declaration only
Implement them in .cpp file with = default:
// animatable_color.cpp#include"core/animation/animator.h"// Full definition here
AnimatableColor::AnimatableColor() = default;
AnimatableColor::~AnimatableColor() = default;
AnimatableColor::AnimatableColor(const AnimatableColor& color) = default;
See: references/forward-declaration-refptr-member.md for detailed solution
Pattern 3: Redefinition Errors
Error signature:
error: redefinition of 'symbol_name'
Common causes:
Multiple definitions across translation units
Missing inline/constexpr for header-only definitions
ODR violations
Historical Cases
All cases are organized by problem type in references/ directory.
error: member access into incomplete type 'OHOS::Ace::Animator'
rawPtr_->IncRefCount();
note: in instantiation of member function 'OHOS::Ace::RefPtr<OHOS::Ace::Animator>::RefPtr'
Context: RefPtr<Animator> or WeakPtr<T> used as class member variable
Common causes:
Special member functions (constructor/destructor/copy constructor) defined with = default in header
Compiler instantiates these functions in header, requiring complete type definition
Common mistake: reverting forward declaration and adding full include
Correct Solution: DO NOT revert forward declaration! Use implementation separation:
Keep forward declaration in header: class Animator;
Declare special member functions in header (without = default)
Implement them in .cpp file with = default
Include full definition in .cpp file
Benefits: Reduced header dependencies, faster compilation (57% improvement in example)
Case 7: Test Linking - Missing Source Files
Location: references/test-missing-source-files.md
Error signature:
ld.lld: error: undefined symbol: OHOS::Ace::ClassName::MethodName(...)
>>> referenced by test_file.cpp:123
Context: Linking test executable (e.g., xxx_unittest)
Common causes:
Test BUILD.gn missing required .cpp files in sources
Header optimization moved implementations to .cpp (e.g., StringUtils, LogWrapper)
New implementation files not added to build system
error: member access into incomplete type 'OHOS::Ace::PixelMap'
shadowInfo.pixelMap->GetPixelMapSharedPtr()
^
note: forward declaration of 'OHOS::Ace::PixelMap'
class PixelMap;
Context: Pure data structure (POD struct) contains RefPtr<T> member and needs -> access
Common causes:
Struct contains RefPtr<T> member variable
Code needs to call -> operator on the smart pointer
Direct call to pixelMap->Method() triggers incomplete type error
Cannot use Case 6 approach because struct has no its own .cpp file
error: no member named 'DragEvent' in namespace 'OHOS::Ace'
using OnDragStartFunc = std::function<DragDropBaseInfo(const RefPtr<OHOS::Ace::DragEvent>&, const std::string&)>;
~~~~~~~~~~~~~^
Context: Type defined in parent namespace, used in child namespace
Common causes:
Type DragEvent defined in OHOS::Ace namespace
Using code in OHOS::Ace::NG child namespace
git diff shows deletion of namespace prefix (e.g., - OHOS::Ace::DragEvent)
Someone removed the fully-qualified namespace prefix
Root Cause:
Type is defined in parent namespace (e.g., OHOS::Ace::DragEvent)
Used in child namespace (e.g., OHOS::Ace::NG)
Deleting the namespace prefix causes compiler to search in wrong namespace
Forward declaration in wrong namespace doesn't help
Correct Solutions (in priority order):
Preserve full namespace qualifier (RECOMMENDED):
// In OHOS::Ace::NG namespaceusing OnDragStartFunc = std::function<DragDropBaseInfo(
const RefPtr<OHOS::Ace::DragEvent>&, // ✅ Keep full namespaceconst std::string&)>;
Add forward declaration in correct namespace:
// In header, before OHOS::Ace::NG namespacenamespace OHOS::Ace {
classDragEvent; // ✅ Forward declare in correct namespace
}
// In OHOS::Ace::NG namespaceusing OnDragStartFunc = std::function<DragDropBaseInfo(
const RefPtr<OHOS::Ace::DragEvent>&, // Still need full namespaceconst std::string&)>;
Add header dependency (when complete type needed):
#include"core/components_ng/event/drag_event.h"// In OHOS::Ace::NG namespaceusing OnDragStartFunc = std::function<DragDropBaseInfo(
const RefPtr<OHOS::Ace::DragEvent>&, // Still use full namespaceconst std::string&)>;
⚠️ Critical:
NEVER delete namespace prefixes
Forward declarations MUST be in the same namespace as type definition
If type is in OHOS::Ace, forward declaration must also be in OHOS::Ace
Using code can be in child namespace, but must reference parent namespace
Key Points:
Find complete type definition (not just forward declarations)
Match forward declaration namespace to type definition namespace
Prefer keeping fully-qualified names over adding includes
Helper method encapsulates complete type access
Reduces header dependencies while maintaining clean API
When to use:
✅ Pure data structures (POD struct) with smart pointer members
✅ Need to dereference smart pointer with -> or *
✅ Cannot add .cpp to existing struct
❌ Classes with their own .cpp file (use Case 6 instead)
❌ Only need constructor/destructor (use Case 6 instead)
ld.lld: error: undefined symbol: virtual thunk to OHOS::Ace::TouchEventTarget::~TouchEventTarget()
>>> referenced by ld-temp.o
>>> lto.tmp:(construction vtable for OHOS::Ace::TouchEventTarget-in-OHOS::Ace::V2::ListScrollBarController)
>>> referenced by ld-temp.o
>>> lto.tmp:(construction vtable for OHOS::Ace::TouchEventTarget-in-OHOS::Ace::VerticalDragRecognizer)
Context: Class with virtual functions used as base class, destructor declared in header and implemented in .cpp (forward declaration optimization), LTO (Link Time Optimization) enabled
Common causes:
Class has virtual functions and is used as base class
Forward declaration optimization: destructor in .cpp file (not inline)
LTO creates virtual thunks for derived classes
Virtual thunk symbols not exported from library
Root Cause:
LTO optimizes virtual function tables during linking
Creates virtual thunk symbols to adjust this pointer for derived classes
These virtual thunk symbols must be available at link time
If destructor not inline, LTO-generated virtual thunk may not be exported
Common mistake: reverting to inline destructor (= default in header)
error: no member named 'DragEvent' in namespace 'OHOS::Ace'
using OnDragStartFunc = std::function<DragDropBaseInfo(const RefPtr<OHOS::Ace::DragEvent>&, const std::string&)>;
~~~~~~~~~~~^
Context: std::function template using RefPtr<T> as parameter type
Key features:
RefPtr<T> is a pointer wrapper with fixed size
using alias does NOT immediately instantiate template
Forward declaration works because RefPtr size is known
Actual template instantiation happens in .cpp file
Common causes:
Misconception that std::function requires complete type definition
Not understanding when template instantiation actually occurs
Confusing type alias declaration with template instantiation
Root Cause:
RefPtr<T> has fixed size (pointer size), so forward declaration works
using OnDragStartFunc = ... is just a type alias, not instantiation
Template instantiation only happens when the type is actually used in .cpp
Solution: Use forward declaration in header, full definition in .cpp:
// Header file (gesture_event_hub.h)namespace OHOS::Ace {
classDragEvent; // ✅ Forward declaration only
}
namespace OHOS::Ace::NG {
// Type alias - NO template instantiation hereusing OnDragStartFunc = std::function<DragDropBaseInfo(
const RefPtr<OHOS::Ace::DragEvent>&, // ✅ Works with forward declconst std::string&)>;
}
// Implementation file (gesture_event_hub.cpp)#include"core/gestures/drag_event.h"// ✅ Full definition here// Actual usage - template instantiation happens here
OnDragStartFunc callback = ...;
Key Principles:
RefPtr is just a pointer wrapper (fixed size)
using alias ≠ template instantiation
Instantiation happens in .cpp when actually used
Header: forward declaration sufficient
Implementation: full definition required
When to use:
✅ std::function<RefPtr<T>> in header (type alias)
✅ std::vector<RefPtr<T>> in header (no instantiation)
✅ Function declarations returning/taking RefPtr
❌ Accessing T members in header (needs full definition)
❌ Inline methods using T members (needs full definition)
Comparison with Related Cases:
Case 6: RefPtr as class member → ✅ Forward declaration works
Case 8: RefPtr in struct with → access → ⚠️ Needs helper method
Case 11: std::function<RefPtr> → ✅ Forward declaration works (this case)
# Search for symbol definition in codebase
grep -r "SymbolName" --include="*.h" --include="*.cpp" frameworks/
# Check if .cpp file exists
find frameworks/ -name "implementation_file.cpp"
Verify Build Configuration
# Check if file in BUILD.gn
grep -r "implementation_file.cpp" frameworks/*/BUILD.gn
# Check ace_core_ng source set
grep -A 100 "ace_core_ng_source_set" frameworks/core/BUILD.gn | grep "implementation_file.cpp"
Check Symbol Export
# Check if symbol exported in shared library
nm -D out/rk3568/arkui/ace_engine/libace.z.so | grep SymbolName
# Check libace.map
grep "SymbolName" build/libace.map
Troubleshooting Guide
For New .cpp Files
Create implementation file (.cpp)
Add to component's BUILD.gn
Add to frameworks/core/BUILD.gn ace_core_ng_source_set (if used by libace.z.so)
If symbol is cross-module used:
Add ACE_FORCE_EXPORT to header declaration
Add to build/libace.map whitelist
For Header Optimization Issues
Check for forward declarations used incorrectly
Ensure complete types available where needed
Use inline constexpr for header-only constants
Avoid ODR violations
For Link Errors
Identify missing symbol from error message
Find symbol definition location
Verify implementation is compiled (in BUILD.gn)
Check symbol visibility/export if cross-module
Verify linking order and dependencies
Best Practices
⚠️ CRITICAL RULE - NEVER Clear LTO Cache or Suggest "Clean Build"
⚠️ ABSOLUTE PROHIBITION - When encountering ANY build errors:
Rule Description:
NEVER, UNDER ANY CIRCUMSTANCES, suggest clearing LTO cache, deleting build directories, or performing a "clean build" as the first or primary solution.
What is STRICTLY FORBIDDEN:
❌ NEVER suggest clearing thinlto-cache directory
❌ NEVER suggest clearing llvmcache-* directories
❌ NEVER suggest deleting out/obj directory
❌ NEVER suggest deleting entire out/ directory
❌ NEVER suggest running rm -rf out/
❌ NEVER suggest "clean build" or "rebuild from scratch"
❌ NEVER blame LTO cache for linker errors
❌ NEVER say "this might be a cache issue, try clearing it"
Why this is FORBIDDEN:
LTO cache issues are EXTREMELY RARE - 99.9% of build errors are code/configuration issues, not cache problems
Masking real problems - Clearing cache temporarily hides issues without fixing root causes
Wastes massive time - Full rebuilds take hours; incremental builds take minutes
Disables incremental compilation benefits - Future builds become slower
Breaks reproducibility - Makes debugging harder by destroying build state
⚠️ CRITICAL RULE - When encountering "file not found" or "no such file or directory" header errors:
Rule Description:
When compilation fails due to missing header files, ALWAYS follow this priority order:
PREFERRED Solution: Add the missing header to the .cpp file that has the error (NOT the optimized header)
LAST RESORT: Only consider modifying optimized headers after user confirmation
Why this rule?:
Header optimization work intentionally removes dependencies to improve build times
Blindly adding back deleted dependencies undermines optimization efforts
.cpp files are the correct place to add necessary includes that were removed from headers
Maintains separation between interface (headers) and implementation (.cpp)
How to Detect Optimized Headers:
Before suggesting any header modifications, CHECK if the header file is in an optimization state:
# Check 1: Staged changes (暂存状态)
git status --porcelain | grep "^M.*\.h$"# Check 2: Modified but not staged (修改状态)
git status --porcelain | grep "^ M.*\.h$"# Check 3: Recent commit (最近一笔提交)
git log -1 --name-only --pretty=format:"" | grep "\.h$"# Combined check - all three states:
git status --porcelain | grep "\.h$"# Staged or modified
git diff HEAD~1 --name-only | grep "\.h$"# Changed in last commit
If the header is in ANY of these states:
✅ PREFERRED: Add missing #include to the .cpp file with the error
❌ DO NOT: Suggest adding back the dependency to the optimized header
⚠️ LAST RESORT: If modifying the header is absolutely necessary, MUST ask user first
When to add to .cpp file (PREFERRED):
// ✅ CORRECT - Add to the .cpp file with the compilation error// frameworks/core/components_ng/pattern/search/search_gesture_event_hub.cpp#include"core/events/click_event.h"// Add missing header here// ❌ WRONG - Do NOT add back to optimized headers// frameworks/core/components_ng/event/click_event.h// #include "core/pipeline/base/element.h" // Don't restore deleted dependencies
User Confirmation Template (when header modification might be necessary):
Examples of optimized headers (do NOT modify without confirmation):
animation_utils.h - Animation utility functions
click_event.h - Click event handling
Any header in staged/modified state or recent commit
Detection Workflow:
Step 1: When encountering "file not found" error
# Extract the missing header path from error# Example: error: 'core/pipeline/base/element.h' file not found
Step 2: Check if the referencing file is an optimized header
# Find where this error occurs
grep -r "#include.*element.h" frameworks/core/components_ng/event/click_event.h
# Check if click_event.h is being optimized
git status --porcelain | grep "click_event.h"
git log -1 --name-only | grep "click_event.h"
Step 3: Apply the appropriate solution
If header is optimized → Add to .cpp file
If header is NOT optimized → Can add to header
If uncertain → Ask user with both options
Verification steps:
Check git status for staged/modified headers
Check last commit for header changes
Identify the .cpp file with the compilation error
Add the missing #include to that .cpp file (PREFERRED)
Verify the fix resolves the error
If header modification was necessary, document why
Key Principles:
✅ Preserve header optimization work
✅ Add missing includes to .cpp implementation files
✅ Maintain clean header dependencies
✅ Check git status before suggesting header modifications
❌ DO NOT blindly revert optimization efforts
❌ DO NOT suggest adding deleted dependencies back to headers without checking optimization state
❌ DO NOT modify headers in staged/modified/recent-commit state without user confirmation
Related Skills:
header-optimization: For understanding header optimization patterns
compile-analysis: For analyzing header dependencies
Case 6: RefPtr member forward declaration optimization
Related Cases:
Header optimization work (see: header-optimization skill)
Forward declaration patterns (Case 6: RefPtr member optimization)
Compilation error analysis (Pattern 2: Incomplete Type Errors)
1. ⭐ HIGH PRIORITY RULE - Type Namespace Confusion (PixelMap, etc.)
⚠️ CRITICAL RULE - When encountering type mismatch errors with common class names:
Rule Description:
When error messages show type mismatches for common class names (like PixelMap), ALWAYS verify you're using the correct namespace variant for the code location.
Common Pitfall - PixelMap Namespace Confusion:
In ACE Engine frameworks (frameworks/core/components_ng/, etc.):
✅ CORRECT: OHOS::Ace::PixelMap (wrapper class in base/image/pixel_map.h)
❌ WRONG: OHOS::Media::PixelMap (underlying media class)
Why this happens:
Ace::PixelMap is a wrapper around Media::PixelMap
Designed specifically for ACE Engine frameworks usage
Located at: base/image/pixel_map.h
IDE auto-complete might incorrectly suggest Media::PixelMap
Solution Pattern:
Identify the error location:
Check if file is in frameworks/ directory
Verify it's using framework code patterns
Use correct type:
// ✅ CORRECT for frameworks/#include"base/image/pixel_map.h"
RefPtr<PixelMap> pixelMap_; // OHOS::Ace::PixelMap// ❌ WRONG in frameworks/#include"native_image/imageinfo.h"// Don't include media headers
RefPtr<Media::PixelMap> pixelMap_; // Wrong namespace
Verify usage: RefPtr<PixelMap> or RefPtr<OHOS::Ace::PixelMap>
No Media::PixelMap references in framework code
Virtual function return types match base class
Related Patterns:
Similar issues can occur with other wrapper types
Always check if there's an Ace wrapper before using media types
Frameworks use Ace wrappers, interfaces might use media types
2. Build System Architecture
libace.z.so only links ace_core_ng libraries
Component-specific libraries are not linked to final产物
New .cpp files used by libace.z.so must be in ace_core_ng_source_set
2. Symbol Export Rules ⭐
⚠️ CRITICAL - RULES FOR NON-TEMPLATE CLASSES AND NON-TEMPLATE METHODS:
When encountering "undefined symbol" linker errors for non-template classes and non-template methods, follow these rules in order:
Rule 1: Check if class has ACE_FORCE_EXPORT
First, check if the class definition has ACE_FORCE_EXPORT:
// Case A: Class WITHOUT ACE_FORCE_EXPORTclassPaddingPropertyF { // ← No export on classfloatWidth()const;
};
// Case B: Class WITH ACE_FORCE_EXPORTclassACE_FORCE_EXPORT PaddingPropertyF { // ← Export on entire classfloatWidth()const;
};
Rule 2: Apply export based on class export status
Case A - Class WITHOUT ACE_FORCE_EXPORT:
✅ Add ACE_FORCE_EXPORT to method declaration in header (PREFERRED)
❌ DO NOT add to method definition in .cpp
Reason: Keeps export control at declaration level, supports fine-grained export control
⭐ Easier maintenance - Clear which symbols are part of API contract
Decision Tree:
Linker Error: undefined symbol ClassName::MethodName
↓
Is ClassName a non-template class?
YES → Is class declaration has ACE_FORCE_EXPORT?
YES → ✅ Class already exported
→ Add ClassName::* to libace.map
→ DONE (no individual method exports needed)
NO → ✅ Add ACE_FORCE_EXPORT to method declaration in .h
→ Add ClassName::MethodName* to libace.map
→ DONE
NO → Use template export rules (see below)
Comparison: Non-Template vs Template
Aspect
Non-Template Class/Method
Template Class/Method
Export location
Method declaration in .h (Rule 2)
Both declaration in .h AND definition in .cpp
Class export
Covers all methods if present
Individual methods still need export
libace.map
Fine-grained: ClassName::MethodName*;
Wildcard: ClassName*; or TemplateFunction*;
Reference
This section (Rule 2)
Pattern 1, Scenario 3 & 5
⚠️ TEMPLATE-ONLY RULES (NOT for non-template):
For template classes and template functions ONLY, use different rules:
Template functions (Pattern 1, Scenario 3):
Add ACE_FORCE_EXPORT to BOTH declaration in .h AND implementation in .cpp
Add explicit instantiation in .cpp
Use wildcard in libace.map: void?ClassName::FunctionName*;
Template class methods (Pattern 1, Scenario 5):
Add ACE_FORCE_EXPORT to EACH method implementation in .cpp
Class export alone is NOT sufficient
Use wildcard in libace.map: ClassName*;
DO NOT mix rules:
❌ Do NOT use template rules for non-template classes
❌ Do NOT use non-template rules for template classes
3. Header Optimization
Use inline constexpr for header-only constants
Don't define in both header and .cpp
Forward declarations reduce dependencies but ensure complete type visible at use
⭐ Key Principles - Symbol Export for Cross-Module Usage
When encountering "undefined symbol" linker errors for methods used by other dynamic libraries:
⚠️ IMPORTANT: Distinguish Between Non-Template and Template
Before applying any export rules, FIRST determine the type:
Linker Error: undefined symbol
↓
Is it a non-template class method?
→ YES: Use Non-Template Rules (below)
→ NO: Use Template Rules (Pattern 1, Scenario 3 & 5)
Non-Template Class Methods: Export at Declaration ⭐
✅ PREFERRED for Non-Template - Add ACE_FORCE_EXPORT to method declaration in header (.h):
// interfaces/inner_api/ace_kit/include/ui/properties/ng/measure_property.hclassPaddingPropertyF {
ACE_FORCE_EXPORT floatWidth()const; // ← Add here (PREFERRED)ACE_FORCE_EXPORT floatHeight()const; // ← Add here (PREFERRED)
};
// frameworks/core/components_ng/property/measure_property.cpp// NO ACE_FORCE_EXPORT here for non-template methodsfloatPaddingPropertyF::Width()const{
return left.value_or(0.0f) + right.value_or(0.0f);
}
Why this approach for non-templates?
Fine-grained export control - Export only needed methods
Clear API boundaries - Declaration shows what's exported
Works with libace.map fine-grained rules - Export specific symbols
Consistent with class export semantics - If class has export, no need for individual exports
⚠️ CRITICAL: Check Class Export Status First
// Case A: Class WITHOUT export → Add to individual method declarationsclassPaddingPropertyF {
ACE_FORCE_EXPORT floatWidth()const; // ← Required
};
// Case B: Class WITH export → No individual exports neededclassACE_FORCE_EXPORT PaddingPropertyF { // ← Entire class exportedfloatWidth()const; // Automatically exported, no ACE_FORCE_EXPORT needed
};
❌ DO NOT for Non-Template:
❌ Add ACE_FORCE_EXPORT to method definition in .cpp (unless template)
❌ Add individual method exports if class already has ACE_FORCE_EXPORT
❌ Use template export rules for non-template code
Template-Only: Different Rules Apply ⚠️
For template classes and template functions, use DIFFERENT rules (see Pattern 1, Scenarios 3 & 5):
Rule Type
Non-Template
Template
Export location
Method declaration in .h
BOTH declaration in .h AND definition in .cpp
Class export sufficient?
YES (covers all methods)
NO (individual methods need export)
libace.map pattern
Fine-grained: ClassName::MethodName*;
Wildcard: ClassName*;
Reference
This section
Pattern 1, Scenarios 3 & 5
When to Use Each Approach
Scenario
Recommended Location
Example
Non-template class method
Method declaration in .h
PaddingPropertyF::Width()
Template class method
Both declaration in .h AND implementation in .cpp
LayoutConstraintT<T>::UpdateMaxSizeWithCheck()
Template function
Both declaration in .h AND implementation in .cpp
StringUtils::StringSplitter<T>
Free function (non-template)
Method declaration in .h
StringUtils::TransformStrCase<std::string>
Class with export already
None needed
All methods auto-exported
Real-World Success Cases
Non-Template Methods (PaddingPropertyF):
Added ACE_FORCE_EXPORT to method declarations in .h
Added ACE_FORCE_EXPORT to each method implementation in .cpp
Class export alone NOT sufficient for templates
Wildcard pattern in libace.map: OHOS::Ace::NG::LayoutConstraintT*;
Template Functions (StringUtils):
Added ACE_FORCE_EXPORT to both declaration in .h AND implementation in .cpp
Explicit instantiation in .cpp
Wildcard pattern in libace.map: void?OHOS::Ace::StringUtils::StringSplitter*;
Remember: When fixing linker errors for symbols needed by other modules, try the .cpp implementation approach first before modifying headers.
4. Template Explicit Instantiation ⭐
For template classes with explicit instantiation:
Issue: PaddingPropertyT<CalcLength> symbols not exported, but PaddingPropertyT<Dimension> works
Root Cause: When a type is used as template parameter for explicit instantiation, the type itself must have export attribute
Key Principle:
Template Type Visibility (CalcLength)
↓
Template Specialization (PaddingPropertyT<CalcLength>)
↓
Symbol Export Success/Failure
If CalcLength has no export → Template specialization inherits internal visibility
If CalcLength has ACE_FORCE_EXPORT → Template specialization can export
Solution:
// ❌ BEFORE - Type missing export (fails when used as template parameter)classCalcLength {
std::string ToString()const{ /* inline */ }
};
// ✅ AFTER - Add type-level export (required for template parameters)classACE_FORCE_EXPORT CalcLength { // ← Required when used as template typestd::string ToString()const{ /* inline - keep in header */ }
};
Critical Rules:
Type used as template parameter MUST have export (if type has inline methods)
DO NOT move inline methods to .cpp - keep header optimization
Template methods still need ACE_FORCE_EXPORT in .cpp
Explicit instantiation in .cpp required
When Type-Level Export is Required:
✅ Type has inline methods (ToString, operator==, etc.)
✅ Type is used as template parameter for explicit instantiation
✅ Template instantiation symbols need to be exported to other modules
Reference: See references/template-instantiation-type-export.md for detailed case study
⚠️ IMPORTANT - Header Optimization:
StringUtils refactoring (commit e0fd3724d21) moved ~650 lines from header to .cpp
This is strategic work to improve build times
DO NOT revert by moving inline methods to .cpp
Add type-level exports to solve template parameter export issues
Verification Steps
After user applies the recommended fixes, suggest these verification commands:
# 1. Navigate to OpenHarmony root directory and rebuildcd <openharmony_root>
./build.sh --product-name rk3568 --build-target ace_engine --ccache
# 2. Check for link errors in out/<product>/build.log
grep "ld.lld: error:" out/rk3568/build.log | wc -l
# 3. Verify symbol export (if applicable)
nm -D out/rk3568/arkui/ace_engine/libace.z.so | grep SymbolName
# 4. Extract and check new errors from out/<product>/build.log
foundation/arkui/ace_engine/.claude/skills/build-error-analyzer/script/extract_last_error.sh out/rk3568/build.log
# 5. Read the extracted errors:cat out/rk3568/last_error.log
# For SDK builds (⚠️ use out/sdk/ directory):# 1. Build SDK: ./build.sh --product-name ohos-sdk --ccache# 2. Check errors: grep "error:" out/sdk/build.log | tail -50# 3. Extract errors: foundation/arkui/ace_engine/.claude/skills/build-error-analyzer/script/extract_last_error.sh out/sdk/build.log# 4. Read errors: cat out/sdk/last_error.log
Note: These are suggestions for the user to run manually. Do not execute build commands automatically.
Adding New Cases
When solving new build errors:
Document the error in examples/<case-name>.md
Include:
Error signature
Root cause
Solution steps
Files modified
Verification commands
Update this SKILL.md to reference the new case
Add patterns to "Error Patterns and Solutions" section
Example Usage
Example 1: Successful Build (NO ERRORS)
User: "帮我分析一下构建错误"
Assistant: "I'll analyze the build errors from the OpenHarmony output directory.
⚠️ FIRST, I'll extract the latest errors from build.log:
[STEP 1 - NAVIGATE TO ROOT]
cd <openharmony_root>
[STEP 2 - EXTRACTION - MANDATORY]
foundation/arkui/ace_engine/.claude/skills/build-error-analyzer/script/extract_last_error.sh out/rk3568/build.log
Output:
Extracted latest error block (24 bytes) from out/rk3568/build.log
→ Saved to out/rk3568/last_error.log
[STEP 3 - READ EXTRACTED ERRORS]
Reading out/rk3568/last_error.log...
Content:
build success, no error
[STEP 4 - CHECK FOR SUCCESS]
✅ Build is successful! No errors found.
## ✅ 构建成功
最新的构建已经成功完成,没有发现任何错误。
**构建状态**: 成功
**错误信息**: 无
建议: 您可以继续进行开发或测试工作。
[STOP - DO NOT read other log files like error.log]"
Example 2: Build with Errors
User: "帮我分析一下构建错误"
Assistant: "I'll analyze the build errors from the OpenHarmony output directory.
⚠️ FIRST, I'll extract the latest errors from build.log:
[STEP 1 - NAVIGATE TO ROOT]
cd <openharmony_root>
[STEP 2 - EXTRACTION - MANDATORY]
foundation/arkui/ace_engine/.claude/skills/build-error-analyzer/script/extract_last_error.sh out/rk3568/build.log
Output:
Extracted latest error block (12345 bytes) from out/rk3568/build.log
→ Saved to out/rk3568/last_error.log
[STEP 3 - READ EXTRACTED ERRORS]
Reading out/rk3568/last_error.log...
[STEP 4 - CATEGORIZE]
Identified as: compilation error - undeclared identifier
[STEP 5 - MATCH PATTERNS]
Checking references/ directory for similar patterns...
Found match: references/undefined-symbol-missing-cpp.md
[STEP 6 - PROVIDE RECOMMENDATIONS]
Providing detailed fix recommendations (NOT modifying files)
## 构建错误分析
### 错误类型
编译错误 - 未声明的标识符
### 错误位置
frameworks/core/event/touch_event.cpp:25
### 根本原因
函数被删除但调用点未移除:TouchPoint::CovertId() 已删除,但头文件中仍有声明且多处调用
### 修复建议
**选项1: 恢复函数实现** (推荐)
在 frameworks/core/event/touch_event.cpp 中恢复函数:
**当前代码**: (函数已删除)
**应添加**:
```cpp
void TouchPoint::CovertId()
{
if (sourceTool == SourceTool::PEN) {
originalId = TOUCH_TOOL_BASE_ID + static_cast<int32_t>(sourceTool);
id = id + originalId;
}
}