Automatically import c headers

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
User avatar
idle
Always Here
Always Here
Posts: 5089
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Automatically import c headers

Post by idle »

Now that we've got a c backend we could really use an automated header converter.
So we could just declare xincludefilec and have it preprocess the header and import the functions and constants.
It's been in my to hard basket for a number of years but now that we have gcc tool chain on all platforms it now makes it feasable to do.
juergenkulow
Enthusiast
Enthusiast
Posts: 555
Joined: Wed Sep 25, 2019 10:18 am

Re: Automatically import c headers

Post by juergenkulow »

After which line in purebasic.c do you want to insert #include "file.h" with XIncludeFileC "file.h"?
purebasic.c example
User avatar
idle
Always Here
Always Here
Posts: 5089
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Automatically import c headers

Post by idle »

Your not actually including an .h file
It would be the resultant .pbi preprocessed and translated to pb so it can be where ever you want.
User avatar
skywalk
Addict
Addict
Posts: 3994
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Automatically import c headers

Post by skywalk »

This would be a great feature, but in the headers I use, there are many C macros and #if's.
It forces me to tweak the converted pbi file for naming conflicts and duplicate prototypes for 'A'/'W' strings, etc.
Would this handle that complexity?
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
idle
Always Here
Always Here
Posts: 5089
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Automatically import c headers

Post by idle »

As a compiler tool probably not. But we could always name space the functions in the headers.

When you preprocess an .h file it includes everything required in one file for the target. With all macros and compiler ifs expanded and all types are resolved to their respective base c types.
It doesn't look nice but it's much easier to parse.

You would need to pass the necessary defines on the command line to gcc to get around the A/W string issue.
User avatar
the.weavster
Addict
Addict
Posts: 1537
Joined: Thu Jul 03, 2003 6:53 pm
Location: England

Re: Automatically import c headers

Post by the.weavster »

I was hoping for something similar to SpiderBasic's EnableJS / DisableJS

So including a C header would be:

Code: Select all

EnableC
#include "myheader.h"
DisableC
juergenkulow
Enthusiast
Enthusiast
Posts: 555
Joined: Wed Sep 25, 2019 10:18 am

Re: Automatically import c headers

Post by juergenkulow »

Code: Select all

; Demo #include "myheader.h"
!#include "/tmp/myheader.h" // Please adapt. 
Procedure test()
  !#include "/tmp/myheader.h"  // Please adapt. 
EndProcedure
test()

CompilerIf Not Defined(PB_Compiler_Backend,#PB_Constant)
  CompilerError "Please use PureBasic Version 6.00 Beta1" 
CompilerElseIf #PB_Compiler_Backend<>#PB_Backend_C
  CompilerError "Please use Compiler-Option C Backend."
CompilerEndIf 
purebasic.c: You find the include in main(...) or in f_test() ?!

Code: Select all

//...
int main(int argc, char* argv[]) {
PB_ArgC = argc;
PB_ArgV = argv;
SYS_InitPureBasic();
// 
// !#include "/tmp/myheader.h" // Please adapt. 
#include "/tmp/myheader.h" // Please adapt. 
// test()
integer rr0=f_test();
// 
// CompilerIf Not Defined(PB_Compiler_Backend,#PB_Constant)
SYS_Quit();
}
//...
// Procedure test()
Static integer f_test() {
integer r=0;
// !#include "/tmp/myheader.h"  // Please adapt. 
#include "/tmp/myheader.h"  // Please adapt. 
// EndProcedure
End:
Return r;
}
//...
User avatar
idle
Always Here
Always Here
Posts: 5089
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Automatically import c headers

Post by idle »

@the.weavster
I'm not sure how that works are the functions accessible from pb then or only js.

I would much prefer that the c is accessible from pb and to port the headers. But It's not that easy, c is quite complex to parse but it would opens up the whole c eco system to pb users which would be a major win. Especially for the raspberry pi and Linux.
User avatar
idle
Always Here
Always Here
Posts: 5089
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Automatically import c headers

Post by idle »

Ok this works on linux, it's not very pretty but it works.

Code: Select all

CompilerIf Not Defined(PB_Compiler_Backend,#PB_Constant)
  CompilerError "Please use PureBasic Version 6.00 Beta1" 
CompilerElseIf #PB_Compiler_Backend<>#PB_Backend_C
  CompilerError "Please use Compiler-Option C Backend."
CompilerEndIf 

ImportC "-lportaudio" : EndImport 
!#include "/usr/include/portaudio.h" // Please adapt. 

Structure paTestData
  left_phase.f;
  right_phase.f;
EndStructure

Global *stream;
Global err 
Global num_seconds= 4;
Global sample_rate = 44100;
Global *output
Global mData.PaTestData 

;** This routine will be called by the PortAudio engine when audio is needed.
;** It may called at interrupt level on some machines so don't do anything
;** that could mess up the system like calling malloc() Or free().
Procedure patestCallback(*inputBuffer,*outputBuffer,framesPerBuffer,*timeInfo,statusFlags,*userData.paTestData)
  
  *out.float = *outputBuffer;
  
  Protected i
  
  For i=0 To framesPerBuffer
    *out\f = *userData\left_phase;  /* left */
    *out+4
    *out\f = *userData\right_phase;  /* right */
    *out+4
    ;/* Generate simple sawtooth phaser that ranges between -1.0 And 1.0. */
    *userData\left_phase + 0.01
    ;/* When signal reaches top, drop back down. */
    If *userData\left_phase >= 1.0 
      *userData\left_phase - 1.0
    EndIf   
    ;higher pitch so we can distinguish left And right. */
    *userData\right_phase + 0.03
    If *userData\right_phase >= 1.0
      *userData\right_phase = -1.0;
    EndIf
    
  Next   
EndProcedure ;

Procedure pa_Init()
  Protected ret 
  !v_ret = Pa_Initialize(); 
  ProcedureReturn ret 
EndProcedure

Procedure Pa_Terminate()
  !Pa_Terminate();
EndProcedure   

Global paCallback = @patestCallback()     

Debug "PortAudio Test: output sawtooth wave."

!v_err = Pa_Initialize(); 
If err <> 0
  Goto error;
EndIf   

!v_err = Pa_OpenDefaultStream(&p_stream,0,2,paFloat32,v_sample_rate,16,v_pacallback,&v_mdata); 
If err <> 0 
  Goto error;
EndIf  

!v_err = Pa_StartStream(p_stream);
If err <> 0
  Goto error;
EndIf   

!Pa_Sleep(v_num_seconds*1000);
!v_err = Pa_StopStream(p_stream );
If err <> 0 
  Goto error;
EndIf   

!v_err = Pa_CloseStream(p_stream);
If err <> paNoError 
  Goto error;
EndIf   

Pa_Terminate();
Debug "Test finished"
End  

error:
Pa_Terminate();
Debug "An error occured while using the portaudio stream"
Debug "error number " + Str(err) 
!p_output = Pa_GetErrorText(v_err);
Debug PeekS(*output,-1,#PB_UTF8) 

User avatar
the.weavster
Addict
Addict
Posts: 1537
Joined: Thu Jul 03, 2003 6:53 pm
Location: England

Re: Automatically import c headers

Post by the.weavster »

idle wrote: Wed Jan 05, 2022 7:59 pm @the.weavster
I'm not sure how that works are the functions accessible from pb then or only js.
Actually looking at your and juergen's code above I think maybe what I'm asking for already works just by using the ! line prefix :oops:

Just to clarify though...
A variable works with the v_ prefix, exactly as it does in SpiderBasic

Code: Select all

  Protected ret 
  !v_ret = Pa_Initialize();
.
but does the p_ prefix in C denote a pointer declared in PB?:

Code: Select all

Global *output
...
!p_output = Pa_GetErrorText(v_err);
User avatar
idle
Always Here
Always Here
Posts: 5089
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Automatically import c headers

Post by idle »

Yes p_pointer and v_var. Constants need to be globals unless you only use the c define inline
juergenkulow
Enthusiast
Enthusiast
Posts: 555
Joined: Wed Sep 25, 2019 10:18 am

Re: Automatically import c headers

Post by juergenkulow »

Using Procedure generates error: conflicting types For ‘Pa_GetErrorText’:

Code: Select all

; ImportC, #include DemoErr with const char *Pa_GetErrorText( PaError errorCode )
ImportC "/tmp/pa_front2.o" : EndImport ; Please adapt.
!#include "/tmp/portaudio/include/portaudio.h" // Please adapt. 

Procedure.s DemoErr(err)
  ;!#include "/tmp/portaudio/include/portaudio.h" // Please adapt.
  Protected *output
  !p_output = Pa_GetErrorText(v_err);
  ProcedureReturn PeekS(*output,-1,#PB_UTF8) 
EndProcedure

s.s=DemoErr(0)  ; paNoError
Debug s

CompilerIf Not Defined(PB_Compiler_Backend,#PB_Constant)
  CompilerError "Please use PureBasic Version 6.00 Beta1" 
CompilerElseIf #PB_Compiler_Backend<>#PB_Backend_C
  CompilerError "Please use Compiler-Option C Backend."
CompilerEndIf 

; with #inclcude after ImportC without #include in Procedure 
; Error: Assembler
; error: conflicting types For ‘Pa_GetErrorText’
;  const char *Pa_GetErrorText( PaError errorCode );
;              ^~~~~~~~~~~~~~~
; purebasic.c:87:12: note: previous implicit declaration of ‘Pa_GetErrorText’ was here
;  p_output = Pa_GetErrorText(v_err);
;             ^~~~~~~~~~~~~~~
; purebasic.c: In function ‘SYS_Quit’:
; purebasic.c:139:1: warning: implicit declaration of function ‘exit’ [-Wimplicit-function-declaration]
;  exit(PB_ExitCode);
;  ^~~~
; purebasic.c:139:1: warning: incompatible implicit declaration of built-in function ‘exit’
; purebasic.c:139:1: note: include ‘<stdlib.h>’ Or provide a declaration of ‘exit’

; with #include in Procedure 
; Success
pa_front2.c

Code: Select all

#include "portaudio.h"

const char *Pa_GetErrorText( PaError errorCode )
{
    const char *result;

    switch( errorCode )
    {
    case paNoError:                  result = "Success"; break;
    case paNotInitialized:           result = "PortAudio not initialized"; break;
    /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError. see: http://www.portaudio.com/trac/ticket/114 */
    case paUnanticipatedHostError:   result = "Unanticipated host error"; break;
    case paInvalidChannelCount:      result = "Invalid number of channels"; break;
    case paInvalidSampleRate:        result = "Invalid sample rate"; break;
    case paInvalidDevice:            result = "Invalid device"; break;
    case paInvalidFlag:              result = "Invalid flag"; break;
    case paSampleFormatNotSupported: result = "Sample format not supported"; break;
    case paBadIODeviceCombination:   result = "Illegal combination of I/O devices"; break;
    case paInsufficientMemory:       result = "Insufficient memory"; break;
    case paBufferTooBig:             result = "Buffer too big"; break;
    case paBufferTooSmall:           result = "Buffer too small"; break;
    case paNullCallback:             result = "No callback routine specified"; break;
    case paBadStreamPtr:             result = "Invalid stream pointer"; break;
    case paTimedOut:                 result = "Wait timed out"; break;
    case paInternalError:            result = "Internal PortAudio error"; break;
    case paDeviceUnavailable:        result = "Device unavailable"; break;
    case paIncompatibleHostApiSpecificStreamInfo:   result = "Incompatible host API specific stream info"; break;
    case paStreamIsStopped:          result = "Stream is stopped"; break;
    case paStreamIsNotStopped:       result = "Stream is not stopped"; break;
    case paInputOverflowed:          result = "Input overflowed"; break;
    case paOutputUnderflowed:        result = "Output underflowed"; break;
    case paHostApiNotFound:          result = "Host API not found"; break;
    case paInvalidHostApi:           result = "Invalid host API"; break;
    case paCanNotReadFromACallbackStream:       result = "Can't read from a callback stream"; break;
    case paCanNotWriteToACallbackStream:        result = "Can't write to a callback stream"; break;
    case paCanNotReadFromAnOutputOnlyStream:    result = "Can't read from an output only stream"; break;
    case paCanNotWriteToAnInputOnlyStream:      result = "Can't write to an input only stream"; break;
    case paIncompatibleStreamHostApi: result = "Incompatible stream host API"; break;
    case paBadBufferPtr:             result = "Bad buffer pointer"; break;
    default:
        if( errorCode > 0 )
            result = "Invalid error code (value greater than zero)";
        else
            result = "Invalid error code";
        break;
    }
    return result;
}

User avatar
idle
Always Here
Always Here
Posts: 5089
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Automatically import c headers

Post by idle »

Im not sure what the problem is. How did you compile the c code?
Maybe i should find another library that's easy to find binaries for windows and osx.
juergenkulow
Enthusiast
Enthusiast
Posts: 555
Joined: Wed Sep 25, 2019 10:18 am

Re: Automatically import c headers

Post by juergenkulow »

Please check if TCC would be suitable for this?
User avatar
idle
Always Here
Always Here
Posts: 5089
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Automatically import c headers

Post by idle »

Libtcc may be usable, tcc has been around for awhile I will look into it. In the mean time I've found a python tool that converts to json its written by one of the developers of llvm and after a quick look It should be possible to use it and port the json to pb.
Post Reply