From 1d44899a9f76332f9a6637a1228d50475a51263a Mon Sep 17 00:00:00 2001 From: Romain Calascibetta Date: Mon, 23 May 2022 16:44:51 +0200 Subject: [PATCH 01/14] Update src/unix/config/discover.exe to recognize pthread without flags In some contexts, the C compiler can integrate few -I and -L and pthread becomes standalone from the user's point-of-view. However, in the context of a C cross-compiler, standalone pthread's definitions can be different than the host system (available into [default_search_paths]) and they can clash. This patch allow us to compile a C code without any flags and let the C (cross?)-compiler to solve by itself where is pthread. This behavior is added from what src/unix/config/discover.exe did before. --- src/unix/config/discover.ml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/unix/config/discover.ml b/src/unix/config/discover.ml index bd528cad7..3542b366f 100644 --- a/src/unix/config/discover.ml +++ b/src/unix/config/discover.ml @@ -368,15 +368,19 @@ struct Output.{name = feature.macro_name; found} end - let compiles ?(werror = false) ?(link_flags = []) context code = - let c_flags = C_library_flags.c_flags () in + let compiles ?(werror = false) ?c_flags ?link_flags context code = + let c_flags = match c_flags with + | None -> C_library_flags.c_flags () + | Some c_flags -> c_flags in let c_flags = if werror then "-Werror"::c_flags else c_flags in - let link_flags = link_flags @ (C_library_flags.link_flags ()) in + let link_flags = match link_flags with + | None -> C_library_flags.link_flags () + | Some link_flags -> link_flags in Configurator.c_test context ~c_flags ~link_flags code |> fun result -> Some result @@ -469,11 +473,14 @@ struct When targeting Android, compiling without -lpthread is the only way to link with pthread, and we don't to search for libpthread, because if we find it, it is likely the host's libpthread. *) - match compiles context code with - | Some true -> Some true - | no -> + match compiles ~c_flags:[] ~link_flags:[] context code, + compiles context code with + | Some true, Some true -> Some true + | Some false, Some true + | Some true, Some false -> Some true + | _no -> if !Arguments.android_target = Some true then - no + Some false else begin match compiles context code ~link_flags:["-lpthread"] with | Some true -> @@ -516,6 +523,7 @@ struct struct msghdr msg; msg.msg_controllen = 0; msg.msg_control = 0; + unsigned char *data = CMSG_DATA(CMSG_FIRSTHDR(&msg)); return 0; } |} From 913e59bbf20119616d28390f5dc53af8b81e7df2 Mon Sep 17 00:00:00 2001 From: Romain Calascibetta Date: Mon, 23 May 2022 16:51:13 +0200 Subject: [PATCH 02/14] {AF,PF}_{UNIX,INET,INET6} are not constants for the Cosmopolitan libc This patch use if/else if/else instead of a switch ... case which expects constants. These values are not constants from the Cosmopolitan libc which set these variables at the "boot" of the application and set them with the right value according to the running system. --- src/unix/unix_c/unix_get_network_information_utils.c | 10 +++------- src/unix/unix_c/unix_mcast_modify_membership.c | 8 +++----- src/unix/unix_c/unix_mcast_set_loop.c | 8 +++----- src/unix/unix_c/unix_mcast_set_ttl.c | 8 +++----- src/unix/unix_c/unix_mcast_utils.c | 7 +++---- 5 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/unix/unix_c/unix_get_network_information_utils.c b/src/unix/unix_c/unix_get_network_information_utils.c index 12248dcd5..ab2fcaf19 100644 --- a/src/unix/unix_c/unix_get_network_information_utils.c +++ b/src/unix/unix_c/unix_get_network_information_utils.c @@ -139,16 +139,12 @@ value alloc_host_entry(struct hostent *entry) res = caml_alloc_small(4, 0); Field(res, 0) = name; Field(res, 1) = aliases; - switch (entry->h_addrtype) { - case PF_UNIX: + if (entry->h_addrtype == PF_UNIX) { Field(res, 2) = Val_int(0); - break; - case PF_INET: + } else if (entry->h_addrtype == PF_INET) { Field(res, 2) = Val_int(1); - break; - default: /*PF_INET6 */ + } else { Field(res, 2) = Val_int(2); - break; } Field(res, 3) = addr_list; End_roots(); diff --git a/src/unix/unix_c/unix_mcast_modify_membership.c b/src/unix/unix_c/unix_mcast_modify_membership.c index febb5ac8f..c6c4d076d 100644 --- a/src/unix/unix_c/unix_mcast_modify_membership.c +++ b/src/unix/unix_c/unix_mcast_modify_membership.c @@ -30,8 +30,7 @@ CAMLprim value lwt_unix_mcast_modify_membership(value fd, value v_action, t = socket_domain(fd_sock); r = 0; - switch (t) { - case PF_INET: { + if (t == PF_INET) { struct ip_mreq mreq; if (caml_string_length(group_addr) != 4 || @@ -55,11 +54,10 @@ CAMLprim value lwt_unix_mcast_modify_membership(value fd, value v_action, r = setsockopt(fd_sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq)); - break; } - default: + else { caml_invalid_argument("lwt_unix_mcast_modify_membership"); - }; + } if (r == -1) uerror("setsockopt", Nothing); diff --git a/src/unix/unix_c/unix_mcast_set_loop.c b/src/unix/unix_c/unix_mcast_set_loop.c index bbf423165..34784ba37 100644 --- a/src/unix/unix_c/unix_mcast_set_loop.c +++ b/src/unix/unix_c/unix_mcast_set_loop.c @@ -22,14 +22,12 @@ CAMLprim value lwt_unix_mcast_set_loop(value fd, value flag) f = Bool_val(flag); r = 0; - switch (t) { - case PF_INET: + if (t == PF_INET) { r = setsockopt(Int_val(fd), IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&f, sizeof(f)); - break; - default: + } else { caml_invalid_argument("lwt_unix_mcast_set_loop"); - }; + } if (r == -1) uerror("setsockopt", Nothing); diff --git a/src/unix/unix_c/unix_mcast_set_ttl.c b/src/unix/unix_c/unix_mcast_set_ttl.c index 78cdf2d79..85dfa06df 100644 --- a/src/unix/unix_c/unix_mcast_set_ttl.c +++ b/src/unix/unix_c/unix_mcast_set_ttl.c @@ -24,14 +24,12 @@ CAMLprim value lwt_unix_mcast_set_ttl(value fd, value ttl) v = Int_val(ttl); r = 0; - switch (t) { - case PF_INET: + if (t == PF_INET) { r = setsockopt(fd_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&v, sizeof(v)); - break; - default: + } else { caml_invalid_argument("lwt_unix_mcast_set_ttl"); - }; + } if (r == -1) uerror("setsockopt", Nothing); diff --git a/src/unix/unix_c/unix_mcast_utils.c b/src/unix/unix_c/unix_mcast_utils.c index ef752c977..5fa59402c 100644 --- a/src/unix/unix_c/unix_mcast_utils.c +++ b/src/unix/unix_c/unix_mcast_utils.c @@ -26,12 +26,11 @@ int socket_domain(int fd) l = sizeof(addr); if (getsockname(fd, &addr.s_gen, &l) == -1) uerror("getsockname", Nothing); - switch (addr.s_gen.sa_family) { - case AF_INET: + if (addr.s_gen.sa_family == AF_INET) { return PF_INET; - case AF_INET6: + } else if (addr.s_gen.sa_family == AF_INET6) { return PF_INET6; - default: + } else { caml_invalid_argument("Not an Internet socket"); } From 37f255f5701dd3e2fa9d370317613efbd0c470a4 Mon Sep 17 00:00:00 2001 From: Romain Calascibetta Date: Mon, 23 May 2022 16:54:21 +0200 Subject: [PATCH 03/14] MADV_* are not constants for the Cosmopolitan libc Instead of a static & global array, we moved the array of MADV_* values into the function which uses it. --- src/unix/unix_c/unix_madvise.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/unix/unix_c/unix_madvise.c b/src/unix/unix_c/unix_madvise.c index f619a4441..f54987a35 100644 --- a/src/unix/unix_c/unix_madvise.c +++ b/src/unix/unix_c/unix_madvise.c @@ -12,8 +12,11 @@ #include #include -static int advise_table[] = { - MADV_NORMAL, MADV_RANDOM, MADV_SEQUENTIAL, MADV_WILLNEED, MADV_DONTNEED, +CAMLprim value lwt_unix_madvise(value val_buffer, value val_offset, + value val_length, value val_advice) +{ + int advise_table[] = { + MADV_NORMAL, MADV_RANDOM, MADV_SEQUENTIAL, MADV_WILLNEED, MADV_DONTNEED, #if defined(MADV_MERGEABLE) MADV_MERGEABLE, #else @@ -34,11 +37,8 @@ static int advise_table[] = { #else 0, #endif -}; + }; -CAMLprim value lwt_unix_madvise(value val_buffer, value val_offset, - value val_length, value val_advice) -{ int ret = madvise((char *)Caml_ba_data_val(val_buffer) + Long_val(val_offset), Long_val(val_length), advise_table[Int_val(val_advice)]); From bda51aa48f0d72948f718b482d4684810a0a4420 Mon Sep 17 00:00:00 2001 From: Romain Calascibetta Date: Mon, 23 May 2022 16:56:32 +0200 Subject: [PATCH 04/14] TC* are not constants for the Cosmopolitan libc Instead of a static & global array, we moved the array of TC* values into the function which uses it. --- src/unix/unix_c/unix_tcflow_job.c | 32 +++++++++++++++--------------- src/unix/unix_c/unix_tcflush_job.c | 28 +++++++++++++------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/unix/unix_c/unix_tcflow_job.c b/src/unix/unix_c/unix_tcflow_job.c index 764fe3c57..f8d783086 100644 --- a/src/unix/unix_c/unix_tcflow_job.c +++ b/src/unix/unix_c/unix_tcflow_job.c @@ -30,22 +30,6 @@ #include #include -/* +-----------------------------------------------------------------+ - | Converters | - +-----------------------------------------------------------------+ */ - -/* Table mapping constructors of ocaml type Unix.flow_action to C values. */ -static int flow_action_table[] = { - /* Constructor TCOOFF. */ - TCOOFF, - /* Constructor TCOON. */ - TCOON, - /* Constructor TCIOFF. */ - TCIOFF, - /* Constructor TCION. */ - TCION -}; - /* +-----------------------------------------------------------------+ | Asynchronous job | +-----------------------------------------------------------------+ */ @@ -94,6 +78,22 @@ static value result_tcflow(struct job_tcflow* job) /* The stub creating the job structure. */ CAMLprim value lwt_unix_tcflow_job(value fd, value action) { +/* +-----------------------------------------------------------------+ + | Converters | + +-----------------------------------------------------------------+ */ + +/* Table mapping constructors of ocaml type Unix.flow_action to C values. */ +int flow_action_table[] = { + /* Constructor TCOOFF. */ + TCOOFF, + /* Constructor TCOON. */ + TCOON, + /* Constructor TCIOFF. */ + TCIOFF, + /* Constructor TCION. */ + TCION +}; + /* Allocate a new job. */ struct job_tcflow* job = lwt_unix_new(struct job_tcflow); /* Initializes function fields. */ diff --git a/src/unix/unix_c/unix_tcflush_job.c b/src/unix/unix_c/unix_tcflush_job.c index 9287ca8e8..c4ce02be3 100644 --- a/src/unix/unix_c/unix_tcflush_job.c +++ b/src/unix/unix_c/unix_tcflush_job.c @@ -30,20 +30,6 @@ #include #include -/* +-----------------------------------------------------------------+ - | Converters | - +-----------------------------------------------------------------+ */ - -/* Table mapping constructors of ocaml type Unix.flush_queue to C values. */ -static int flush_queue_table[] = { - /* Constructor TCIFLUSH. */ - TCIFLUSH, - /* Constructor TCOFLUSH. */ - TCOFLUSH, - /* Constructor TCIOFLUSH. */ - TCIOFLUSH -}; - /* +-----------------------------------------------------------------+ | Asynchronous job | +-----------------------------------------------------------------+ */ @@ -92,6 +78,20 @@ static value result_tcflush(struct job_tcflush* job) /* The stub creating the job structure. */ CAMLprim value lwt_unix_tcflush_job(value fd, value queue) { + /* +-----------------------------------------------------------------+ + | Converters | + +-----------------------------------------------------------------+ */ + + /* Table mapping constructors of ocaml type Unix.flush_queue to C values. */ + int flush_queue_table[] = { + /* Constructor TCIFLUSH. */ + TCIFLUSH, + /* Constructor TCOFLUSH. */ + TCOFLUSH, + /* Constructor TCIOFLUSH. */ + TCIOFLUSH + }; + /* Allocate a new job. */ struct job_tcflush* job = lwt_unix_new(struct job_tcflush); /* Initializes function fields. */ From db0acf15f46257ded3f0e9ddb53d97c23549c962 Mon Sep 17 00:00:00 2001 From: Romain Calascibetta Date: Mon, 23 May 2022 16:57:44 +0200 Subject: [PATCH 05/14] WNOHANG & WUNTRACED are not constants for the Cosmopolitan libc Instead of a static & global array, we moved the array of WNOHANG & WUNTRACED values into the function which uses it. --- src/unix/unix_c/unix_wait4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/unix_c/unix_wait4.c b/src/unix/unix_c/unix_wait4.c index daa9ab4f4..c0e86eab5 100644 --- a/src/unix/unix_c/unix_wait4.c +++ b/src/unix/unix_c/unix_wait4.c @@ -58,13 +58,13 @@ static value alloc_process_status(int status) return st; } -static int wait_flag_table[] = {WNOHANG, WUNTRACED}; - value lwt_unix_wait4(value flags, value pid_req) { CAMLparam1(flags); CAMLlocal2(times, res); + int wait_flag_table[] = {WNOHANG, WUNTRACED}; + int pid, status, cv_flags; cv_flags = caml_convert_flag_list(flags, wait_flag_table); From 461086293cfc7f7da0f141096697e013b11b2913 Mon Sep 17 00:00:00 2001 From: Romain Calascibetta Date: Mon, 23 May 2022 17:01:26 +0200 Subject: [PATCH 06/14] speeds & termios values are not constants for the Cosmopolitan libc This patch create 2 C functions to initialize an array with speed values or termios values. If we pass NULL to these functions, they returns the length of the array. By this way, we initiate required arrays which contains speeds & termios value at the runtime - instead of the compile time. This patch is needed because these values are not constants for the Cosmopolitan libc and we must set/initialize arrays at runtime. --- src/unix/unix_c/unix_termios_conversion.c | 180 +++++++++++++--------- 1 file changed, 104 insertions(+), 76 deletions(-) diff --git a/src/unix/unix_c/unix_termios_conversion.c b/src/unix/unix_c/unix_termios_conversion.c index e9b82f8e6..7f5abca21 100644 --- a/src/unix/unix_c/unix_termios_conversion.c +++ b/src/unix/unix_c/unix_termios_conversion.c @@ -20,141 +20,161 @@ enum { Iflags, Oflags, Cflags, Lflags }; /* Structure of the terminal_io record. Cf. unix.mli */ -static long terminal_io_descr[] = { - /* Input modes */ - Bool, Iflags, IGNBRK, Bool, Iflags, BRKINT, Bool, Iflags, IGNPAR, Bool, - Iflags, PARMRK, Bool, Iflags, INPCK, Bool, Iflags, ISTRIP, Bool, Iflags, - INLCR, Bool, Iflags, IGNCR, Bool, Iflags, ICRNL, Bool, Iflags, IXON, Bool, - Iflags, IXOFF, - /* Output modes */ - Bool, Oflags, OPOST, - /* Control modes */ - Speed, Output, Speed, Input, Enum, Cflags, 5, 4, CSIZE, CS5, CS6, CS7, CS8, - Enum, Cflags, 1, 2, CSTOPB, 0, CSTOPB, Bool, Cflags, CREAD, Bool, Cflags, - PARENB, Bool, Cflags, PARODD, Bool, Cflags, HUPCL, Bool, Cflags, CLOCAL, - /* Local modes */ - Bool, Lflags, ISIG, Bool, Lflags, ICANON, Bool, Lflags, NOFLSH, Bool, - Lflags, ECHO, Bool, Lflags, ECHOE, Bool, Lflags, ECHOK, Bool, Lflags, - ECHONL, - /* Control characters */ - Char, VINTR, Char, VQUIT, Char, VERASE, Char, VKILL, Char, VEOF, Char, VEOL, - Char, VMIN, Char, VTIME, Char, VSTART, Char, VSTOP, End}; +static tcflag_t *choose_field(struct termios *terminal_status, long field) +{ + switch (field) { + case Iflags: + return &terminal_status->c_iflag; + case Oflags: + return &terminal_status->c_oflag; + case Cflags: + return &terminal_status->c_cflag; + case Lflags: + return &terminal_status->c_lflag; + default: + return 0; + } +} -static struct { +struct speed_t { speed_t speed; int baud; -} speedtable[] = {{B50, 50}, - {B75, 75}, - {B110, 110}, - {B134, 134}, - {B150, 150}, +}; + +long _speedtable(struct speed_t dst[]) { + struct speed_t speedtable[] = { + {B50, 50}, + {B75, 75}, + {B110, 110}, + {B134, 134}, + {B150, 150}, #ifdef B200 - {B200, 200}, + {B200, 200}, #endif - {B300, 300}, - {B600, 600}, - {B1200, 1200}, - {B1800, 1800}, - {B2400, 2400}, - {B4800, 4800}, - {B9600, 9600}, - {B19200, 19200}, - {B38400, 38400}, + {B300, 300}, + {B600, 600}, + {B1200, 1200}, + {B1800, 1800}, + {B2400, 2400}, + {B4800, 4800}, + {B9600, 9600}, + {B19200, 19200}, + {B38400, 38400}, #ifdef B57600 - {B57600, 57600}, + {B57600, 57600}, #endif #ifdef B115200 - {B115200, 115200}, + {B115200, 115200}, #endif #ifdef B230400 - {B230400, 230400}, + {B230400, 230400}, #endif - {B0, 0}, + {B0, 0}, /* Linux extensions */ #ifdef B460800 - {B460800, 460800}, + {B460800, 460800}, #endif #ifdef B500000 - {B500000, 500000}, + {B500000, 500000}, #endif #ifdef B576000 - {B576000, 576000}, + {B576000, 576000}, #endif #ifdef B921600 - {B921600, 921600}, + {B921600, 921600}, #endif #ifdef B1000000 - {B1000000, 1000000}, + {B1000000, 1000000}, #endif #ifdef B1152000 - {B1152000, 1152000}, + {B1152000, 1152000}, #endif #ifdef B1500000 - {B1500000, 1500000}, + {B1500000, 1500000}, #endif #ifdef B2000000 - {B2000000, 2000000}, + {B2000000, 2000000}, #endif #ifdef B2500000 - {B2500000, 2500000}, + {B2500000, 2500000}, #endif #ifdef B3000000 - {B3000000, 3000000}, + {B3000000, 3000000}, #endif #ifdef B3500000 - {B3500000, 3500000}, + {B3500000, 3500000}, #endif #ifdef B4000000 - {B4000000, 4000000}, + {B4000000, 4000000}, #endif - /* MacOS extensions */ + /* MacOS extensions */ #ifdef B7200 - {B7200, 7200}, + {B7200, 7200}, #endif #ifdef B14400 - {B14400, 14400}, + {B14400, 14400}, #endif #ifdef B28800 - {B28800, 28800}, + {B28800, 28800}, #endif #ifdef B76800 - {B76800, 76800}, + {B76800, 76800}, #endif /* Cygwin extensions (in addition to the Linux ones) */ #ifdef B128000 - {B128000, 128000}, + {B128000, 128000}, #endif #ifdef B256000 - {B256000, 256000}, + {B256000, 256000}, #endif -}; + }; -#define NSPEEDS (sizeof(speedtable) / sizeof(speedtable[0])) + if (dst != NULL) memcpy(dst, speedtable, sizeof(speedtable)); + return (sizeof(speedtable) / sizeof(speedtable[0])); +} -static tcflag_t *choose_field(struct termios *terminal_status, long field) -{ - switch (field) { - case Iflags: - return &terminal_status->c_iflag; - case Oflags: - return &terminal_status->c_oflag; - case Cflags: - return &terminal_status->c_cflag; - case Lflags: - return &terminal_status->c_lflag; - default: - return 0; - } +long _terminal_io_descr(long dst[]) { + long terminal_io_descr[] = { + /* Input modes */ + Bool, Iflags, IGNBRK, Bool, Iflags, BRKINT, Bool, Iflags, IGNPAR, Bool, + Iflags, PARMRK, Bool, Iflags, INPCK, Bool, Iflags, ISTRIP, Bool, Iflags, + INLCR, Bool, Iflags, IGNCR, Bool, Iflags, ICRNL, Bool, Iflags, IXON, Bool, + Iflags, IXOFF, + /* Output modes */ + Bool, Oflags, OPOST, + /* Control modes */ + Speed, Output, Speed, Input, Enum, Cflags, 5, 4, CSIZE, CS5, CS6, CS7, CS8, + Enum, Cflags, 1, 2, CSTOPB, 0, CSTOPB, Bool, Cflags, CREAD, Bool, Cflags, + PARENB, Bool, Cflags, PARODD, Bool, Cflags, HUPCL, Bool, Cflags, CLOCAL, + /* Local modes */ + Bool, Lflags, ISIG, Bool, Lflags, ICANON, Bool, Lflags, NOFLSH, Bool, + Lflags, ECHO, Bool, Lflags, ECHOE, Bool, Lflags, ECHOK, Bool, Lflags, + ECHONL, + /* Control characters */ + Char, VINTR, Char, VQUIT, Char, VERASE, Char, VKILL, Char, VEOF, Char, VEOL, + Char, VMIN, Char, VTIME, Char, VSTART, Char, VSTOP, End}; + + if (dst != NULL) memcpy(dst, terminal_io_descr, sizeof(terminal_io_descr)); + return (sizeof(terminal_io_descr) / sizeof(long)); } + void encode_terminal_status(struct termios *terminal_status, volatile value *dst) { long *pc; int i; + long _NSPEEDS = _speedtable(NULL); + struct speed_t speedtable[_NSPEEDS]; + _speedtable(speedtable); + + long nterminal_io_descr = _terminal_io_descr(NULL); + long terminal_io_descr[nterminal_io_descr]; + _terminal_io_descr(terminal_io_descr); + for (pc = terminal_io_descr; *pc != End; dst++) { switch (*pc++) { case Bool: { @@ -190,7 +210,7 @@ void encode_terminal_status(struct termios *terminal_status, volatile value *dst speed = cfgetispeed(terminal_status); break; } - for (i = 0; i < NSPEEDS; i++) { + for (i = 0; i < _NSPEEDS; i++) { if (speed == speedtable[i].speed) { *dst = Val_int(speedtable[i].baud); break; @@ -212,6 +232,14 @@ int decode_terminal_status(struct termios *terminal_status, volatile value *src) long *pc; int i; + long _NSPEEDS = _speedtable(NULL); + struct speed_t speedtable[_NSPEEDS]; + _speedtable(speedtable); + + long nterminal_io_descr = _terminal_io_descr(NULL); + long terminal_io_descr[nterminal_io_descr]; + _terminal_io_descr(terminal_io_descr); + for (pc = terminal_io_descr; *pc != End; src++) { switch (*pc++) { case Bool: { @@ -242,7 +270,7 @@ int decode_terminal_status(struct termios *terminal_status, volatile value *src) int which = *pc++; int baud = Int_val(*src); int res = 0; - for (i = 0; i < NSPEEDS; i++) { + for (i = 0; i < _NSPEEDS; i++) { if (baud == speedtable[i].baud) { switch (which) { case Output: From bc804ee38315c0c480855cf76aa7b410190dc5d3 Mon Sep 17 00:00:00 2001 From: Romain Calascibetta Date: Wed, 1 Jun 2022 12:05:39 +0200 Subject: [PATCH 07/14] Some _SC* macros are not available from the Cosmopolitan libc This patch is probably the more invasive about Esperanto/Cosmopolitan. It adds a new compilation path when [__ESPERANTO__] is defined. A note was added to explain where it comes from: the cross-compiler [arch-esperanto-none-static-cc] systematically defines [-D__ESPERANTO__] in order to let third-party libraries (such as lwt) to choose different compilation paths. And here we are! Cosmopolitan does not defines required [_SC*] constants and [unix_get_pw_gr_nam_id_job] can not be compiled. We discard this piece of code when we want to compile with Cosmopolitan as it's the case for Android too. --- src/unix/unix_c/unix_get_pw_gr_nam_id_job.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/unix/unix_c/unix_get_pw_gr_nam_id_job.c b/src/unix/unix_c/unix_get_pw_gr_nam_id_job.c index 579686d17..974dbac93 100644 --- a/src/unix/unix_c/unix_get_pw_gr_nam_id_job.c +++ b/src/unix/unix_c/unix_get_pw_gr_nam_id_job.c @@ -20,7 +20,11 @@ #include "lwt_unix.h" -#if !defined(__ANDROID__) +/* NOTE: [__ESPERANTO__] is defined by the cross-compiler if we compile into + * the [esperanto] context (with [arch-esperanto-none-static-cc]). Otherwise, + * nobody should define this macro. The code above can not be compiled with + * Esperanto/Cosmopolitan due to missing [_SC*] macros. */ +#if !defined(__ANDROID__) && !defined(__ESPERANTO__) static value alloc_passwd_entry(struct passwd *entry) { From f5ecec9e87e1a9cdc81a6a9124226a7d6ce2d948 Mon Sep 17 00:00:00 2001 From: Romain Calascibetta Date: Wed, 1 Jun 2022 12:11:03 +0200 Subject: [PATCH 08/14] Re-update src/unix/config/discover.exe to be able to cross-compile lwt The default case of [C_library_flags.detect] puts systematically [-I/usr/include] and [-L/usr/lib] even in a cross-compilation context which is wrong because [/usr/include/pthread.h] can clash [cross-env/pthread.h] for instance. The default case about underlying libraries (libev or pthread) should be available only from a restrictive set of flags instead of a pervasive one. This patch restricts this set to what we really need instead to pervasively picks some random flags. A clarification about the recognition of [pthread] was made too to really understand the behavior of [discover.exe] and give a chance to be more reproducible afterwards --- src/unix/config/discover.ml | 73 +++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/src/unix/config/discover.ml b/src/unix/config/discover.ml index 3542b366f..bc2849c68 100644 --- a/src/unix/config/discover.ml +++ b/src/unix/config/discover.ml @@ -160,6 +160,8 @@ sig val ws2_32_lib : Configurator.t -> unit + val set_c_flags : string list -> unit + val set_link_flags : string list -> unit val c_flags : unit -> string list val link_flags : unit -> string list val add_link_flags : string list -> unit @@ -249,14 +251,19 @@ struct | None -> try - let path = + let _path = List.find (fun path -> Sys.file_exists (path // "include" // header)) (Lazy.force search_paths) in + (* NOTE: for the cross-compilation sake, we should not arbitrarily + * include ([-I]) some paths which can clash some cross-compilation's + * definitions with host's definitions. The default case about flags + * should always be less than more - and we should put these flags + * only we really require them. *) extend - ["-I" ^ (path // "include")] - ["-L" ^ (path // "lib"); "-l" ^ library] + [] (* ["-I" ^ (path // "include")] *) + [] (* ["-L" ^ (path // "lib"); "-l" ^ library] *) with Not_found -> () @@ -268,6 +275,9 @@ struct else extend unicode ["-lws2_32"] + let set_c_flags lst = c_flags := lst + let set_link_flags lst = link_flags := lst + let c_flags () = !c_flags @@ -440,6 +450,7 @@ struct C_library_flags.add_link_flags ["-lev"]; Some true | _ -> + C_library_flags.add_link_flags ["-lev"]; C_library_flags.detect context ~library:"ev"; compiles context code end @@ -463,26 +474,48 @@ struct } |} in - (* On some platforms, pthread is included in the standard library, but - linking with -lpthread fails. So, try to link the test code without - any flags first. - - If that fails and we are not targeting Android, try to link with - -lpthread. If *that* fails, search for libpthread in the filesystem. - - When targeting Android, compiling without -lpthread is the only way - to link with pthread, and we don't to search for libpthread, because - if we find it, it is likely the host's libpthread. *) - match compiles ~c_flags:[] ~link_flags:[] context code, - compiles context code with - | Some true, Some true -> Some true - | Some false, Some true - | Some true, Some false -> Some true + (* To clarify the semantic of the recognition of [pthread]: + 1) [pthread] can be _standalone_ (included in the standard library) + depending on the C compiler + 1.1) A restrictive context (such as a cross-compilation context) + requires, at least, [-lpthread] but [-I] and [-L] can + disturb the compilation between the host's [pthread] and the + cross-compiled [pthread]. We test above all and for all this + tricky context with **only one** flag [-lpthread] + 1.2) On some platforms, if [pthread] is standalone, the linker + fails when we link with [-lpthread]. So we test our code + with **default** flags (such as [-I/usr/include] and + [-L/usr/lib]) and **without** [-pthread] + 2) On Android, compiling without [-lpthread] is the only way to link + with [pthread], and we don't to search for [pthread.a], because + if we find it, it is likely the host's [pthread] + 3) We finally retest our code with [-lpthread] and basic [-L] and + [-I] flags (from the host system) + + NOTE(dinosaure): + - 2) and 1.1) should be merged, we definitely should try to compile + the code **without any flags** and see results - by this way, we + consider that the _toolchain_ leads us about where is + [pthread]. + - 3) is too ~vague~ and obviously works but it's difficult to really + understand which [pthread] we really use. + - A question remains about priorities: do we want to prioritize + the [dune]'s context or do we prefer a compilation for the host + system first? + - In anyway, [discover.exe] should be less pervasives (no [ref] + about flags) and more strict and reproducible *) + match (* 1.2 *) compiles context code, + (* 1.1 *) compiles ~c_flags:[] ~link_flags:[ "-lpthread" ] context code with + | _, Some true (* prioritize [dune]'s context and cross-compilation *) -> + C_library_flags.set_c_flags [] ; + C_library_flags.set_link_flags [ "-lpthread" ] ; + Some true + | Some true, _ -> Some true | _no -> - if !Arguments.android_target = Some true then + if (* 2 *) !Arguments.android_target = Some true then Some false else begin - match compiles context code ~link_flags:["-lpthread"] with + match (* 3 *) compiles context code ~link_flags:["-lpthread"] with | Some true -> C_library_flags.add_link_flags ["-lpthread"]; Some true From 447a05ebf4db838e42c7a396eda71c3d7938a970 Mon Sep 17 00:00:00 2001 From: Romain Calascibetta Date: Wed, 1 Jun 2022 15:22:58 +0200 Subject: [PATCH 09/14] Search and use libev **after** pthreads If we consider pthread as the default implementation needed by lwt, we should prioritize the recognition of [pthread] before [libev] but more concretely, due to the undeterministic behavior of [discover.exe] and our usage of [C_library_flags.set_{c,link}_flags] to reset any flags when we can link [pthread] from a cross-compiler, it seems that we reset aggregate flags needed for [libev] (specially [-lev]) in the same time. This patch aggregate flags needed for [pthread] first and let the recognition of [libev] then. However, that mostly means that in the context of the cross-compilation, the user must NOT install [conf-libev] (otherwise, we will try to link with the host's [libev] which is obviously incompatible with our cross-compiler). This patch wants to keep, as much as we can, the same behavior - but it highlights limits of [discover.exe]. --- src/unix/config/discover.ml | 104 ++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/src/unix/config/discover.ml b/src/unix/config/discover.ml index bc2849c68..5123e17a1 100644 --- a/src/unix/config/discover.ml +++ b/src/unix/config/discover.ml @@ -404,58 +404,6 @@ struct | Some true -> None | _ -> k () - let () = feature { - pretty_name = "libev"; - macro_name = "HAVE_LIBEV"; - detect = fun context -> - let detect_esy_wants_libev () = - match Sys.getenv "cur__target_dir" with - | exception Not_found -> None - | _ -> - match Sys.getenv "LIBEV_CFLAGS", Sys.getenv "LIBEV_LIBS" with - | exception Not_found -> Some false - | "", "" -> Some false - | _ -> Some true - in - - let should_look_for_libev = - match !Arguments.use_libev with - | Some argument -> - argument - | None -> - match detect_esy_wants_libev () with - | Some result -> - result - | None -> - (* we're not under esy *) - let os = Configurator.ocaml_config_var_exn context "os_type" in - os <> "Win32" && !Arguments.android_target <> Some true - in - - if not should_look_for_libev then - None - else begin - let code = {| - #include - - int main() - { - ev_default_loop(0); - return 0; - } - |} - in - match compiles context code ~link_flags:["-lev"] with - | Some true -> - C_library_flags.add_link_flags ["-lev"]; - Some true - | _ -> - C_library_flags.add_link_flags ["-lev"]; - C_library_flags.detect context ~library:"ev"; - compiles context code - end - } - let () = feature { pretty_name = "pthread"; macro_name = "HAVE_PTHREAD"; @@ -526,6 +474,58 @@ struct end } + let () = feature { + pretty_name = "libev"; + macro_name = "HAVE_LIBEV"; + detect = fun context -> + let detect_esy_wants_libev () = + match Sys.getenv "cur__target_dir" with + | exception Not_found -> None + | _ -> + match Sys.getenv "LIBEV_CFLAGS", Sys.getenv "LIBEV_LIBS" with + | exception Not_found -> Some false + | "", "" -> Some false + | _ -> Some true + in + + let should_look_for_libev = + match !Arguments.use_libev with + | Some argument -> + argument + | None -> + match detect_esy_wants_libev () with + | Some result -> + result + | None -> + (* we're not under esy *) + let os = Configurator.ocaml_config_var_exn context "os_type" in + os <> "Win32" && !Arguments.android_target <> Some true + in + + if not should_look_for_libev then + None + else begin + let code = {| + #include + + int main() + { + ev_default_loop(0); + return 0; + } + |} + in + match compiles context code ~link_flags:("-lev" :: C_library_flags.link_flags ()) with + | Some true -> + C_library_flags.add_link_flags ["-lev"]; + Some true + | _ -> + (* C_library_flags.add_link_flags ["-lev"]; *) + C_library_flags.detect context ~library:"ev"; + compiles context code + end + } + let () = feature { pretty_name = "eventfd"; macro_name = "HAVE_EVENTFD"; From d9d5a6d3a9124aa1dcaa978a945dc0e5429f97e1 Mon Sep 17 00:00:00 2001 From: Romain Calascibetta Date: Mon, 13 Jun 2022 17:50:52 +0200 Subject: [PATCH 10/14] Add a GitHub action for Esperanto --- .github/workflows/esperanto.yml | 102 ++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 .github/workflows/esperanto.yml diff --git a/.github/workflows/esperanto.yml b/.github/workflows/esperanto.yml new file mode 100644 index 000000000..a3539ff15 --- /dev/null +++ b/.github/workflows/esperanto.yml @@ -0,0 +1,102 @@ +name: Esperanto support +on: [ push ] +jobs: + test: + strategy: + matrix: + operating-system: [ ubuntu-latest ] + ocaml-version: [ "4.13.1", "4.14.0" ] + local-packages: + - | + *.opam + !lwt_domain.opam + runs-on: ${{ matrix.operating-system }} + steps: + - uses: actions/checkout@v2 + - uses: ocaml/setup-ocaml@v2 + with: + ocaml-compiler: ${{ matrix.ocaml-version }} + opam-local-packages: ${{ matrix.local-packages }} + - name: Fix binfmt and Cosmopolitan + run: sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register" + - name: Install Esperanto, Dune & ocamlfind + run: opam install esperanto.0.0.3 dune ocamlfind + - name: Install opam-monorepo + run: opam install opam-monorepo + - name: Add opam-monorepo overlays + run: opam repo add dune-universe git+https://github.com/dune-universe/opam-overlays.git + - name: Example with lwt & esperanto + run: | + mkdir esperanto-example + cd esperanto-example + cat >dune-workspace <dune-project <cat.ml <>= fun len' -> + if len - len' > 0 + then full_write fd buf (off + len') (len - len') + else Lwt.return_unit + + let tmp = Bytes.create 0x1000 + + let rec cat () = + Lwt.catch begin fun () -> + Lwt_unix.read Lwt_unix.stdin tmp 0 (Bytes.length tmp) >>= fun len -> + match len with + | 0 -> Lwt.return_unit + | len -> full_write Lwt_unix.stdout tmp 0 len >>= cat + end @@ function + | End_of_file -> Lwt.return_unit + | exn -> raise exn + + let () = Lwt_main.run (cat ()) + EOF + cat >dune <cat.opam <" ] + authors: [ "Romain Calascibetta " ] + homepage: "https://github.com/dinosaure/esperanto" + bug-reports: "https://github.com/dinosaure/esperanto/issues" + dev-repo: "git+https://github.com/dinosaure/esperanto" + doc: "https://dinosaure.github.io/esperanto/" + license: "MIT" + synopsis: "The cat.com tool produced by esperanto" + description: "The cat.com tool produced by esperanto" + + build: [ + [ "dune" "build" "-p" name "-j" jobs ] + ] + install: [ + [ "dune" "install" "-p" name ] {with-test} + ] + + depends: [ + "ocaml" {>= "4.12.0"} + "dune" {>= "2.8.0"} + "lwt" + ] + EOF + opam monorepo lock --ocaml-version ${{ matrix.ocaml-version }} + opam monorepo pull + opam exec -- dune build -x esperanto ./cat.exe + objcopy -S -O binary _build/default.esperanto/cat.exe cat.com + ./cat.com < cat.ml From dcf80f199f57cb479ecba3f147343142e3335bc0 Mon Sep 17 00:00:00 2001 From: Calascibetta Romain Date: Mon, 6 Feb 2023 11:47:25 +0100 Subject: [PATCH 11/14] {R,W,X,F}_OK are not constants for the Cosmopolitan libc --- src/unix/unix_c/unix_access_job.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/unix/unix_c/unix_access_job.c b/src/unix/unix_c/unix_access_job.c index a054fc34c..91a8b0334 100644 --- a/src/unix/unix_c/unix_access_job.c +++ b/src/unix/unix_c/unix_access_job.c @@ -33,21 +33,21 @@ | Converters | +-----------------------------------------------------------------+ */ -/* Table mapping constructors of ocaml type Unix.access_permission to C values. */ -static int access_permission_table[] = { - /* Constructor R_OK. */ - R_OK, - /* Constructor W_OK. */ - W_OK, - /* Constructor X_OK. */ - X_OK, - /* Constructor F_OK. */ - F_OK -}; - /* Convert ocaml values of type Unix.access_permission to a C int. */ static int int_of_access_permissions(value list) { + /* Table mapping constructors of ocaml type Unix.access_permission to C values. */ + int access_permission_table[] = { + /* Constructor R_OK. */ + R_OK, + /* Constructor W_OK. */ + W_OK, + /* Constructor X_OK. */ + X_OK, + /* Constructor F_OK. */ + F_OK + }; + int result = 0; while (list != Val_emptylist) { result |= access_permission_table[Int_val(Field(list, 0))]; From e10e2b8890c97d721500f928f2098257b941bfeb Mon Sep 17 00:00:00 2001 From: Calascibetta Romain Date: Mon, 6 Feb 2023 11:48:11 +0100 Subject: [PATCH 12/14] Open flags are not constants for the Cosmopolitan libc --- src/unix/unix_c/unix_open_job.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/unix/unix_c/unix_open_job.c b/src/unix/unix_c/unix_open_job.c index a77ad1cab..0c1dc27a8 100644 --- a/src/unix/unix_c/unix_open_job.c +++ b/src/unix/unix_c/unix_open_job.c @@ -35,19 +35,8 @@ #define caml_unix_cloexec_default unix_cloexec_default #endif -static int open_flag_table[] = { - O_RDONLY, O_WRONLY, O_RDWR, O_NONBLOCK, O_APPEND, O_CREAT, O_TRUNC, - O_EXCL, O_NOCTTY, O_DSYNC, O_SYNC, O_RSYNC, 0, /* O_SHARE_DELETE, - Windows-only */ - 0, /* O_CLOEXEC, treated specially */ - 0 /* O_KEEPEXEC, treated specially */ -}; - enum { CLOEXEC = 1, KEEPEXEC = 2 }; -static int open_cloexec_table[15] = {0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, CLOEXEC, KEEPEXEC}; - struct job_open { struct lwt_unix_job job; int flags; @@ -112,6 +101,18 @@ static value result_open(struct job_open *job) CAMLprim value lwt_unix_open_job(value name, value flags, value perms) { + int open_flag_table[] = { + O_RDONLY, O_WRONLY, O_RDWR, O_NONBLOCK, O_APPEND, O_CREAT, O_TRUNC, + O_EXCL, O_NOCTTY, O_DSYNC, O_SYNC, O_RSYNC, 0, /* O_SHARE_DELETE, + Windows-only */ + 0, /* O_CLOEXEC, treated specially */ + 0 /* O_KEEPEXEC, treated specially */ + }; + + + int open_cloexec_table[15] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, CLOEXEC, KEEPEXEC}; + LWT_UNIX_INIT_JOB_STRING(job, open, 0, name); job->fd = caml_convert_flag_list(flags, open_cloexec_table); job->flags = caml_convert_flag_list(flags, open_flag_table); From 869b8d41662b79114918719e7b0413f9112d4f60 Mon Sep 17 00:00:00 2001 From: Calascibetta Romain Date: Mon, 13 Mar 2023 11:39:53 +0100 Subject: [PATCH 13/14] Fix the compilation of termios_conversion with esperanto The last release of esperanto does not define speed_t constants. We must protect the definition of our speed_t table when the toolchain is esperanto. --- src/unix/unix_c/unix_termios_conversion.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/unix/unix_c/unix_termios_conversion.c b/src/unix/unix_c/unix_termios_conversion.c index 7f5abca21..7e292576f 100644 --- a/src/unix/unix_c/unix_termios_conversion.c +++ b/src/unix/unix_c/unix_termios_conversion.c @@ -41,16 +41,21 @@ struct speed_t { int baud; }; +/* XXX(dinosaure): esperanto **does not** defines [speed_t] constants. */ + long _speedtable(struct speed_t dst[]) { struct speed_t speedtable[] = { +#ifndef __ESPERANTO__ {B50, 50}, {B75, 75}, {B110, 110}, {B134, 134}, {B150, 150}, +#endif // __ESPERANTO__ #ifdef B200 {B200, 200}, #endif +#ifndef __ESPERANTO__ {B300, 300}, {B600, 600}, {B1200, 1200}, @@ -60,6 +65,7 @@ long _speedtable(struct speed_t dst[]) { {B9600, 9600}, {B19200, 19200}, {B38400, 38400}, +#endif // __ESPERANTO__ #ifdef B57600 {B57600, 57600}, #endif @@ -69,7 +75,9 @@ long _speedtable(struct speed_t dst[]) { #ifdef B230400 {B230400, 230400}, #endif +#ifndef __ESPERANTO__ {B0, 0}, +#endif // __ESPERANTO__ /* Linux extensions */ #ifdef B460800 From 1de3f907c22de566a3e90ddff762e830252d4fc7 Mon Sep 17 00:00:00 2001 From: Calascibetta Romain Date: Mon, 13 Mar 2023 11:40:52 +0100 Subject: [PATCH 14/14] Disable errors when we try to compile the pthread example with esperanto Currently, the Cosmopolitan/Esperanto toolchain protects the usage of pthread and we are not able to pass to it 0. This patch allows us to compile (and recognize the support of pthread) the code with the esperanto toolchain. --- src/unix/config/discover.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/config/discover.ml b/src/unix/config/discover.ml index 5123e17a1..eb37ef357 100644 --- a/src/unix/config/discover.ml +++ b/src/unix/config/discover.ml @@ -417,7 +417,7 @@ struct int main() { - pthread_create(0, 0, 0, 0); + pthread_create(1, 1, 1, 1); return 0; } |}