Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linenoise compilation with cpp #3720

Closed
def- opened this issue Jan 14, 2016 · 12 comments
Closed

linenoise compilation with cpp #3720

def- opened this issue Jan 14, 2016 · 12 comments

Comments

@def-
Copy link
Member

def- commented Jan 14, 2016

Currently rdstdin can't be compiled with the cpp target because it uses linenoise, which is a C library that fails when compiled as C++.

I see two choices:

  1. Make linenoise compilable as C++, see C++ compilation antirez/linenoise#87
  2. Make the compiler recognize .c file endings, similar to what's done already with .asm, and then invoke the C compiler instead of C++

I guess 2 is the better choice.

@Araq
Copy link
Member

Araq commented Jan 15, 2016

I thought (2) is implicitly done by the C compiler we invoke but I guess we call 'g++' for all of these but it works with clang?

@def-
Copy link
Member Author

def- commented Jan 15, 2016

On my system it works with neither --cc:gcc nor --cc:clang.

@Araq Araq closed this as completed in b4d6346 Jan 17, 2016
@def-
Copy link
Member Author

def- commented Jan 17, 2016

Still doesn't compile for me with cpp, but new error now:

import rdstdin
discard readLineFromStdin("> ")
nimcache/stdlib_rdstdin.o: In function `readlinefromstdin_139001(NimStringDesc*)':
stdlib_rdstdin.cpp:(.text+0x100): undefined reference to `linenoise(char*)'
stdlib_rdstdin.cpp:(.text+0x1ae): undefined reference to `linenoiseHistoryAdd(char*)'
collect2: error: ld returned 1 exit status
Error: execution of an external program failed: 'g++   -o x  nimcache/stdlib_unsigned.o nimcache/stdlib_parseutils.o nimcache/stdlib_strutils.o nimcache/stdlib_times.o nimcache/stdlib_posix.o nimcache/stdlib_termios.o nimcache/stdlib_linenoise.o nimcache/stdlib_rdstdin.o nimcache/x.o nimcache/stdlib_system.o nimcache/clinenoise.o  -ldl'

This is because these functions use a const char* parameter instead of a char* one:

char *linenoise(const char *prompt);
int linenoiseHistoryAdd(const char *line);

Again not sure how best to fix this.

@def- def- reopened this Jan 17, 2016
@Araq
Copy link
Member

Araq commented Jan 17, 2016

Make the prototypes agree? No idea what the problem is, works for me with clang.

@def-
Copy link
Member Author

def- commented Jan 17, 2016

How do I express const char* in Nim? Doesn't work for me with clang 3.7.1 either.

@timotheecour
Copy link
Member

timotheecour commented Dec 26, 2020

How do I express const char* in Nim? Doesn't work for me with clang 3.7.1 either.

option 1:

lib/system/io.nim:
proc wfopen(filename, mode: WideCString): pointer {.importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}

option 2:

or codegenDecl
(more details needed)

option 3:

(pending #12150, separate header would not be needed)

// t11579b.h
#include <stdio.h>
void fn(const char* a, char b) {
  printf("%s %c\n", a, b);
}
type cstring_const* {.importcpp:"const char*".} = cstring
# pending https://github.com/nim-lang/Nim/issues/12150, {.emit.} would be sufficient 
proc fn(a: cstring_const, b: char) {.importcpp: "$1(@)", header: "t11579b.h".} = discard
proc main=
  var a = "abc".cstring
  fn(cast[cstring_const](a), 'b')
main()

@xflywind can you please help me document this in https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-importcpp-pragma ?

@ringabout
Copy link
Member

@timotheecour
All right

@ringabout
Copy link
Member

ringabout commented Dec 26, 2020

@timotheecour
But it is not perfect, cstring can pass compilation too.

type cstring_const* {.importcpp:"const char*".} = cstring
# pending https://github.com/nim-lang/Nim/issues/12150, {.emit.} would be sufficient 
proc fn(a: cstring_const, b: char) {.importcpp: "$1(@)", header: "t11579b.h".} = discard
proc main=
  var a = "abc".cstring
  fn(a, 'b')
main()

distinct cstring doesn't generate const char*

type cstring_const* {.importcpp:"const char*".} = distinct cstring
# pending https://github.com/nim-lang/Nim/issues/12150, {.emit.} would be sufficient 
proc fn(a: cstring_const, b: char) {.importcpp: "$1(@)", header: "t11579b.h".} = discard
proc main=
  var a = cstring_const("abc".cstring)
  fn(a, 'b')
main()

@timotheecour
Copy link
Member

timotheecour commented Dec 27, 2020

I found a solution; adapted from your distinct idea:

// t11579b.h
#include <stdio.h>
void fn(const char* a, char b) {
  printf("v1 %s %c\n", a, b);
}
void fn(char* a, char b) {
  printf("v2 %s %c\n", a, b);
}
# main.nim
when true:
  type cstringConstImpl {.importcpp:"const char*".} = cstring
  type cstringConst = distinct cstringConstImpl
  proc fn(a: cstringConst, b: char) {.importcpp: "$1(@)", header: "t11579b.h".} = discard

  var a = "abc".cstring
  fn(cast[cstringConst](a), 'b')
  doAssert not compiles(fn(a, 'b'))

  proc fn(a: cstring, b: char) {.importcpp: "$1(@)", header: "t11579b.h".} = discard
  fn(a, 'b')

prints:
v1 abc b
v2 abc b

note

maybe we could support in future the shortcut:
type foo {.importcpp:"const char*".} = distinct cstring
(likewise, would be nice to support the shortcut type Foo {.importcpp:"Foo".} = ref object)

@ringabout
Copy link
Member

ringabout commented Dec 28, 2020

Final example

{.emit: """
#include <stdio.h>
int fn(const char* a, char b) {
  return 1;
}

int fn(char* a, char b) {
  return 2;
}
"""
.}

type
  cstringConstImpl {.importcpp:"const char*".} = cstring
  constChar* = distinct cstringConstImpl

proc fn(a: constChar, b: char): int {.importcpp: "$1(@)".} = discard
proc fn(a: cstring, b: char): int {.importcpp: "$1(@)".} = discard


var a = constChar("abs")
doAssert fn(a, 'b') == 1
var b = cstring("abc")
doAssert fn(b, 'b') == 2

Wrapper const char* for C/C++ backend

{.emit: """
int fn(const char* a, char b) {
  return 1;
}
"""
.}


type
  cstringConstImpl {.importc:"const char*".} = cstring
  constChar* = distinct cstringConstImpl

proc fn(a: constChar, b: char): int {.importc: "fn", nodecl.}

var x = constChar("abc")
doAssert fn(x, 'c') == 1
doAssert not compiles(fn("abc", 'b'))
doAssert not compiles(fn("abc".cstring, 'b'))

Generates:

/* section: NIM_merge_VARS */
N_LIB_PRIVATE const char* x__4x9bQioQdm79c9a2t8uhnty3A = "abc";

@timotheecour
Copy link
Member

timotheecour commented Dec 28, 2020

Final example

good; a few notes:

# t11600b.h:
template <typename T>
using myOwnMap = const T;

# main.nim:
when true:
  type
    CppConstImpl[T] {.importcpp: "myOwnMap", header: "t11600b.h".} = object
    CppConst*[T] = distinct CppConstImpl[T]
    ConstCharPtr* = ptr CppConst[char]

  {.emit: """
  int fn(const char* a, char b) {
    return 1;
  }
""".}

  proc fn(a: ConstCharPtr, b: char): cint {.importc: "fn", nodecl.}

  # var x = ConstCharPtr("abc")
  var x = cast[ConstCharPtr]("abc")
  doAssert fn(x, 'c') == 1
  doAssert not compiles(fn("abc", 'b'))
  doAssert not compiles(fn("abc".cstring, 'b'))

maybe this should be in some std/cpputils ?

@ringabout
Copy link
Member

ringabout commented Dec 28, 2020

I dnnuo, but I will write a simple article to introduce this.
My second example works for both C and C++ backend.

https://dev.to/xflywind/wrap-const-char-in-the-nim-language-53no

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants