C++ 빠른 시작
C++ Bindgen Quick Start
This guide will get you started with using C++ libraries from Vais in 5 minutes.
Prerequisites
- Vais compiler installed
- C++ compiler (g++, clang++, or MSVC)
- Basic knowledge of C++ and Vais
Step 1: Create a Simple C++ Library
Create a file math.hpp:
// math.hpp
#ifndef MATH_HPP
#define MATH_HPP
class Calculator {
public:
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
};
double square(double x) {
return x * x;
}
#endif
Step 2: Generate Vais Bindings
Run the bindgen tool:
vaisc bindgen math.hpp -o math.vais --cpp
This creates math.vais with the bindings.
Step 3: Create a C++ Implementation File
Create math.cpp:
// math.cpp
#include "math.hpp"
// If you have additional implementation, put it here
// For this example, everything is in the header
Step 4: Compile the C++ Library
On Linux:
g++ -shared -fPIC math.cpp -o libmath.so
On macOS:
clang++ -dynamiclib math.cpp -o libmath.dylib
On Windows:
cl /LD math.cpp
Step 5: Use the Library in Vais
Create main.vais:
# Import the generated bindings
U math
F main() -> i64 {
# Create a Calculator object
calc := Calculator { }
# Call methods (note: need to pass self pointer)
result1 := calc.add(&calc, 10, 20)
printf("10 + 20 = %d\n", result1)
result2 := calc.multiply(&calc, 5, 7)
printf("5 * 7 = %d\n", result2)
# Call standalone function
sq := square(4.5)
printf("4.5^2 = %f\n", sq)
0
}
Step 6: Build and Run
# Build the Vais program and link with the C++ library
vaisc build main.vais -L. -lmath
# Run it
./main
Expected output:
10 + 20 = 30
5 * 7 = 35
4.5^2 = 20.250000
Complete Example with Separate Implementation
Let's do a more realistic example with separate header and implementation.
vector2.hpp
#ifndef VECTOR2_HPP
#define VECTOR2_HPP
class Vector2 {
public:
double x;
double y;
Vector2(double x, double y);
double length() const;
Vector2 add(const Vector2& other) const;
};
#endif
vector2.cpp
#include "vector2.hpp"
#include <cmath>
Vector2::Vector2(double x, double y) : x(x), y(y) {}
double Vector2::length() const {
return std::sqrt(x * x + y * y);
}
Vector2 Vector2::add(const Vector2& other) const {
return Vector2(x + other.x, y + other.y);
}
Generate and build:
# Generate bindings
vaisc bindgen vector2.hpp -o vector2.vais --cpp
# Compile C++ library
g++ -shared -fPIC vector2.cpp -o libvector2.so
Use in Vais (vec_main.vais):
U vector2
F main() -> i64 {
# Create vectors
v1 := Vector2::new(3.0, 4.0)
v2 := Vector2::new(1.0, 2.0)
# Call methods
len1 := v1.length()
printf("Length of v1: %f\n", len1)
# Add vectors
v3 := v1.add(&v2)
printf("v1 + v2 = (%f, %f)\n", v3.x, v3.y)
0
}
Build and run:
vaisc build vec_main.vais -L. -lvector2
./vec_main
Common Patterns
1. Calling Methods
C++ methods require passing this pointer explicitly:
# Wrong:
result := obj.method(arg)
# Correct:
result := obj.method(&obj, arg)
# Or use the impl wrapper:
impl MyClass {
F method(self: *MyClass, arg: i32) -> i32 {
_ZN7MyClass6methodEi(self, arg)
}
}
# Then you can call:
result := obj.method(&obj, arg)
2. Creating Objects
Constructor calls via helper functions:
# The bindgen creates wrapper like this:
impl MyClass {
F new(arg: i32) -> MyClass {
obj := MyClass { /* fields */ }
_ZN7MyClassC1Ei(&obj, arg)
obj
}
}
# Use it:
obj := MyClass::new(42)
3. Working with Pointers
# Pass address with &
method_taking_pointer(&obj)
# Dereference with *
value := *ptr
Troubleshooting
Problem: "cannot find -lmylib"
Solution: Make sure library is in current directory or add path:
vaisc build main.vais -L/path/to/lib -lmylib
Problem: Undefined symbol errors
Solution: Check mangled names match:
nm libmylib.so | grep ClassName
Problem: Segmentation fault
Solution:
- Make sure you're passing pointers correctly
- Check that objects are initialized
- Verify library is compatible (same compiler/ABI)
Next Steps
- Read
CPP_SUPPORT.mdfor detailed feature documentation - See
CPP_IMPLEMENTATION_SUMMARY.mdfor advanced usage - Check
DESIGN.mdfor architecture details
Tips
- Start Simple: Begin with simple structs and functions
- Use extern "C": Avoid name mangling when possible
- Check Bindings: Review generated
.vaisfile - Test Incrementally: Add features one at a time
- Handle Errors: Use Result types for fallible operations
Full Working Example
Here's everything in one place:
simple.hpp:
class Counter {
private:
int count;
public:
Counter() : count(0) {}
void increment() { count++; }
int get() const { return count; }
};
Commands:
# Generate bindings
vaisc bindgen simple.hpp -o simple.vais --cpp
# Compile library
g++ -shared -fPIC simple.hpp -o libsimple.so
# Create Vais program
cat > test.vais << 'EOF'
U simple
F main() -> i64 {
counter := Counter::new()
counter.increment(&counter)
counter.increment(&counter)
counter.increment(&counter)
value := counter.get(&counter)
printf("Count: %d\n", value)
0
}
EOF
# Build and run
vaisc build test.vais -L. -lsimple
./test
Expected output: Count: 3
Success!
You've now successfully:
- Generated bindings from C++ headers
- Compiled a C++ library
- Called C++ code from Vais
- Linked everything together
Happy coding!