Skip to content

Instantly share code, notes, and snippets.

@sumanstats
Last active September 30, 2023 12:20
Show Gist options
  • Save sumanstats/8b20c1b0e323a89359e00a671833974f to your computer and use it in GitHub Desktop.
Save sumanstats/8b20c1b0e323a89359e00a671833974f to your computer and use it in GitHub Desktop.
Raku nativecall

Build cmake with Strawberry Perl

To use Strawberry perl with cmake execute this in Powershell or command prompt (both)

cmake .. -G "MinGW Makefiles" -D CMAKE_C_COMPILER="C:/Strawberry/c/bin/gcc.exe" 
         -D CMAKE_MAKE_PROGRAM="C:/Strawberry/c/bin/gmake.exe"         

The problem is due to not locating make program because doing

cmake .. -G "MinGW Makefiles" -D CMAKE_MAKE_PROGRAM="C:/Strawberry/c/bin/gmake.exe"         

works great.

# cmake configuration to generate dll (dynamic library) in windows
#
# Copyright 2018 The Statslabs Authors.
#
cmake_minimum_required(VERSION 3.16)
project(rmath VERSION 1.0.0 LANGUAGES C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED True)
##################################################
# Create target and set properties
##################################################
set(CMAKE_BUILD_TYPE Release)
include_directories(include)
file(GLOB SOURCES "<folder1>/*.c" "<folder2>/*.c")
# generate shared library
add_library(<libraryname> SHARED
${SOURCES})
# Generate makefiles compatible with GCC in windows with
# mkdir build && cd build && cmake .. -G "MinGW Makefiles" && make
# gcc and make should be in PATH
# also possible to generate MSYS Makefiles in Rtools chain 4.2
.PHONY: test clean
CC=gcc
CFLAGS=-fPIC -O3 -Wall -Werror -Wextra -pedantic #O3 highest level optimisation
all: libhoge.so
libhoge.so: libhoge.o
$(CC) $(CFLAGS) -shared libhoge.o -o $@
libhoge.o: libhoge.c
$(CC) $(CFLAGS) -c libhoge.c -o $@
test: libhoge.so
prove -e "raku -I." test.raku
clean:
rm libhoge.o libhoge.so
# More elegant Makefile using variables and functions
# Note I am in Windows
CC=gcc
CFLAGS=-g -fPIC -O3 -Wall -Werror -Wextra -pedantic
LDFLAGS=-shared
SRC_FILES=$(wildcard src/*.c)
OUT=libtest.dll
.PHONY: $(OUT)
$(OUT): $(SRC_FILES)
$(CC) $(CFLAGS) $(SRC_FILES) $(LDFLAGS) -o $(OUT)
clean:
rm -rf $(OUT)
// This code works with Rcpp in R
// but with raku they say they don't have corresponding data structure in Raku
// this function gives the count of the character in a string
#include <algorithm>
#include <iostream>
#include <string>
int count(std::string myString, char character)
{
return std::count(myString.begin(), myString.end(), character);
}
// The way out is this
// std::string str "This is the string";
// char * cstr = new char [str.length()+1];
// std::strcpy (cstr, str.c_str());
// cstr now contains a c-string copy of str
// C-style string
//const char* cstr = "Techie Delight";
// string constructor accepts `const char*` as a parameter
//std::string s(cstr);
cmake_minimum_required(VERSION 3.22)
project(test1 VERSION 4.1.3 LANGUAGES C DESCRIPTION "Rmath shared standalone library of R")
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED True)
##################################################
# Create target and set properties
##################################################
set(CMAKE_BUILD_TYPE Release)
file(GLOB SOURCES "src/*.c")
# generate shared library
add_library(test1 SHARED ${SOURCES})
set_target_properties(test1 PROPERTIES PREFIX "")
find_package(OpenMP)
if(OpenMP_C_FOUND)
target_link_libraries(test1 PUBLIC OpenMP::OpenMP_C)
endif()
# Generate makefiles compatible with GCC in windows with
# mkdir build && cd build && cmake .. -G "MinGW Makefiles" && make
# also possible to generate MSYS Makefiles in Rtools chain 4.2
# C code
#include <stdio.h>
double _myadd(double *data, int length) {
double sum = 0.0;
for(int i = 0; i < length; i++) {
sum = sum + data[i];
};
return sum;
}
# Raku code
# C code compiled as libtest.so in linux, libtest.dylib in mac
# and libtest.dll in Windows
# Passing raku array to C with NativeCall
use NativeCall;
sub _myadd(CArray[num64], int32) returns num64
is native("./test") {*};
sub myadd(@data) {
my $length = @data.elems;
return _myadd(@data,$length)
}
my @data = [3.14, 2.71, 6e2, 1.61, 3.89];
@data = @data.map: {$_.Num};
my $values = CArray[num64].new(@data);
say myadd($values)
# Another technique
# sub myadd(@data is copy) {
# my $length = @data.elems;
# @data = @data.map: {$_.Num};
# my $values = CArray[num64].new(@data);
# return _myadd($values,$length)
# }
# my @data = [3.14, 2.71, 6e2, 1.61, 3.89];
# say myadd(@data)
/*This contains two C functions sqrt and cbrt from math.h library*/
#include <math.h>
#include <stdio.h>
double mysqrt(int n){
return sqrt(n);
}
double mycuberoot(int n){
return cbrt(n);
}
void custom(){
double no_match = 1;
double matches_me;
int ct;
printf("People\t Matches me\t Any match\n");
for (ct=2; ct<=40; ct ++){
matches_me = 1- pow(364/365., ct-1);
no_match *= (1 - (ct-1)/365.);
printf("%i\t %.3f\t\t %.3f\n", ct, matches_me, (1-no_match));
}
}
#I built .so file with command
#gcc -g -fPIC -Wall -Werror -Wextra -pedantic *.c -shared -o libsum.so
# NOTE: while you are printing the return value of your custom() call,
# it's a void function so it returns nothing, which in raku's NativeCall is represented as the Mu type object
use NativeCall;
sub mysqrt(int32) returns num64 is native('sum') { * };
sub mycuberoot(int32) returns num64 is native('sum') { * };
sub custom() is native('sum') { * };
say mysqrt(89);
say mycuberoot(89);
custom();
# C code
#include <stdio.h>
#include <stdbool.h>
double _variance(double *data, int length, bool sample) {
double x;
int i;
double old_mean;
double mean = data[0];
double sum_of_squares_of_differences_from_the_current_mean = 0.0;
for (i = 1; i < length; i++) {
x = data[i];
old_mean = mean;
double old_sum_of_squares_of_differences_from_the_current_mean = sum_of_squares_of_differences_from_the_current_mean;
mean = old_mean + (x-old_mean)/(i+1);
sum_of_squares_of_differences_from_the_current_mean = old_sum_of_squares_of_differences_from_the_current_mean + (x-mean)*(x-old_mean);
};
if (sample) {
return sum_of_squares_of_differences_from_the_current_mean/(length - 1);
} else {
return sum_of_squares_of_differences_from_the_current_mean/(length);
}
}
# Raku code
# Passing raku array to C with NativeCall
use NativeCall;
sub _variance(CArray[num64], int32, bool) returns num64
is native("./lyang") {*};
sub variance(@data, :$sample = True) {
my $length = @data.elems;
if $sample == True {
return _variance(@data,$length,True)
} else {
return _variance(@data,$length,False)
}
}
my @data = [3.14, 2.71, 6e2, 1.61, 3.89];
@data = @data.map: {$_.Num};
my @values := CArray[num64].new(@data);
say variance(@values, sample => False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment