Skip to content

Commit

Permalink
Use build_config.h instead of -DOCAML_STDLIB_DIR
Browse files Browse the repository at this point in the history
Cygwin no longer provides the iconv command by default, which means the
translation of LIBDIR into OCAML_STDLIB_DIR cannot be guaranteed to
succeed. Technically, an unusual PREFIX could also result in an invalid
C constant in the Unix build.

Introduce a (relatively) small C program to carry out the function of
iconv and also translate the constant on the Unix side as well.
  • Loading branch information
dra27 committed Apr 28, 2021
1 parent 5ba9e0e commit 88676f6
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 26 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ otherlibs/win32unix/readlink.c typo.long-line
otherlibs/win32unix/stat.c typo.long-line
otherlibs/win32unix/symlink.c typo.long-line

runtime/sak.c typo.non-ascii

stdlib/hashbang typo.white-at-eol typo.missing-lf

testsuite/tests/** typo.missing-header typo.long-line=may
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ _build
/runtime/ld.conf
/runtime/.gdb_history
/runtime/.dep
/runtime/build_config.h
/runtime/sak
/runtime/domain_state32.inc
/runtime/domain_state64.inc

Expand Down
6 changes: 6 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,12 @@ OCaml 4.13.0
which runtime to use while building the compilers (Sébastien Hinderer,
review by David Allsopp)

- #10451: Replace the use of iconv with a C utility to convert $(LIBDIR) to a
C string constant on Windows when building the runtime. Hardens the generation
of the constant on Unix for paths with backslashes, double-quotes and
newlines.
(David Allsopp, review by Florian Angeletti and Sébastien Hinderer)

### Bug fixes:

- #6654, #9774, #10401: make `include` and with `constraints` handle correctly
Expand Down
39 changes: 13 additions & 26 deletions runtime/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ NATIVE_C_SOURCES := $(addsuffix .c, \
dynlink clambda_checks afl bigarray \
memprof domain skiplist codefrag)

GENERATED_HEADERS := caml/opnames.h caml/version.h caml/jumptbl.h
GENERATED_HEADERS := caml/opnames.h caml/version.h caml/jumptbl.h build_config.h
CONFIG_HEADERS := caml/m.h caml/s.h

ifeq "$(TOOLCHAIN)" "msvc"
Expand Down Expand Up @@ -105,25 +105,6 @@ libasmrunpic_OBJECTS := $(NATIVE_C_SOURCES:.c=.npic.$(O)) \

# General (non target-specific) assembler and compiler flags

# On Windows, OCAML_STDLIB_DIR needs to be defined dynamically

ifeq "$(UNIX_OR_WIN32)" "win32"
# OCAML_STDLIB_DIR needs to arrive in dynlink.c as a string which both gcc and
# msvc are willing parse without warning. This means we can't pass UTF-8
# directly since, as far as I can tell, cl can cope, but the pre-processor
# can't. So the string needs to be directly translated to L"" form. To do this,
# we take advantage of the fact that Cygwin uses GNU libiconv which includes a
# Java pseudo-encoding which translates any UTF-8 sequences to \uXXXX (and,
# unlike the C99 pseudo-encoding, emits two surrogate values when needed, rather
# than \UXXXXXXXX). The \u is then translated to \x in order to accommodate
# pre-Visual Studio 2013 compilers where \x is a non-standard alias for \u.
OCAML_STDLIB_DIR = $(shell echo $(LIBDIR)| iconv -t JAVA | sed -e 's/\\u/\\x/g')
STDLIB_CPP_FLAG = -DOCAML_STDLIB_DIR='L"$(OCAML_STDLIB_DIR)"'
else # Unix
OCAML_STDLIB_DIR = $(LIBDIR)
STDLIB_CPP_FLAG = -DOCAML_STDLIB_DIR='"$(OCAML_STDLIB_DIR)"'
endif

ifneq "$(CCOMPTYPE)" "msvc"
OC_CFLAGS += -g
endif
Expand Down Expand Up @@ -192,8 +173,8 @@ endif
.PHONY: clean
clean:
rm -f *.o *.obj *.a *.lib *.so *.dll ld.conf
rm -f ocamlrun ocamlrund ocamlruni ocamlruns
rm -f ocamlrun.exe ocamlrund.exe ocamlruni.exe ocamlruns.exe
rm -f ocamlrun ocamlrund ocamlruni ocamlruns sak
rm -f ocamlrun.exe ocamlrund.exe ocamlruni.exe ocamlruns.exe sak.exe
rm -f primitives primitives.new prims.c $(GENERATED_HEADERS)
rm -f domain_state*.inc
rm -rf $(DEPDIR)
Expand Down Expand Up @@ -261,6 +242,16 @@ caml/jumptbl.h : caml/instruct.h
caml/version.h : $(ROOTDIR)/tools/make-version-header.sh $(ROOTDIR)/VERSION
$^ > $@

sak$(EXE): sak.$(O)
$(call MKEXE_USING_COMPILER,$@,$^)

C_LITERAL = $(shell ./sak$(EXE) encode-C-literal '$(1)')

build_config.h: $(ROOTDIR)/Makefile.config sak$(EXE)
echo '/* This file is generated from $(ROOTDIR)/Makefile.config */' > $@
echo '#define OCAML_STDLIB_DIR $(call C_LITERAL,$(LIBDIR))' >> $@
echo '#define HOST "$(HOST)"' >> $@

# Libraries and programs

ocamlrun$(EXE): prims.$(O) libcamlrun.$(A)
Expand Down Expand Up @@ -365,10 +356,6 @@ endif
$(foreach object_type, $(object_types), \
$(eval $(call COMPILE_C_FILE,$(object_type),%)))

dynlink.%.$(O): OC_CPPFLAGS += $(STDLIB_CPP_FLAG)

startup_byt.%.$(O): OC_CPPFLAGS += $(STDLIB_CPP_FLAG) -DHOST='"$(HOST)"'

$(UNIX_OR_WIN32)_non_shared.%.$(O): OC_CPPFLAGS += -DBUILDING_LIBCAMLRUNS

$(eval $(call COMPILE_C_FILE,$(UNIX_OR_WIN32)_non_shared.%,$(UNIX_OR_WIN32)))
Expand Down
2 changes: 2 additions & 0 deletions runtime/dynlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include "caml/prims.h"
#include "caml/signals.h"

#include "build_config.h"

#ifndef NATIVE_CODE

/* The table of primitives */
Expand Down
103 changes: 103 additions & 0 deletions runtime/sak.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**************************************************************************/
/* */
/* OCaml */
/* */
/* David Allsopp, OCaml Labs, Cambridge. */
/* */
/* Copyright 2021 David Allsopp Ltd. */
/* */
/* All rights reserved. This file is distributed under the terms of */
/* the GNU Lesser General Public License version 2.1, with the */
/* special exception on linking described in the file LICENSE. */
/* */
/**************************************************************************/

/* Runtime Builder's Swiss Army Knife. This utility performs functions
previously delegated to classic Unix utilities but which ultimately seem to
cause more hassle for maintenance than the initial simplicity suggests.
This tool is a memorial to the many hours and PRs spent chasing down strange
locale issues, stray CR characters and fighting yet another incompatible
implementation of sed or awk. */

/* Borrow the Unicode *_os definitions and T() macro from misc.h */
#define CAML_INTERNALS
#include "caml/misc.h"

#include <stdio.h>
#include <string.h>

/* Operations
- encode-C-literal. Used for the OCAML_STDLIB_DIR macro in
runtime/build_config.h to ensure the LIBDIR make variable is correctly
represented as a C string literal.
On Unix, `sak encode-C-literal /usr/local/lib` returns `"/usr/local/lib"`
On Windows, `sak encode-C-literal "C:\OCaml🐫\lib"` returns
`L"C:\\OCaml\xd83d\xdc2b\\lib"`
*/

void usage(void)
{
printf(
"OCaml Build System Swiss Army Knife\n"
"Usage: sak command\n"
"Commands:\n"
" * encode-C-literal path - encodes path as a C string literal\n"
);
}

/* Converts the supplied path (UTF-8 on Unix and UCS-2ish on Windows) to a valid
C string literal. On Windows, this is always a wchar_t* (L"..."). */
void encode_C_literal(char_os *path)
{
char_os c;

#ifdef _WIN32
putchar('L');
#endif
putchar('"');

while ((c = *path++) != 0) {
/* Escape \, " and \n */
if (c == '\\') {
printf("\\\\");
} else if (c == '"') {
printf("\\\"");
} else if (c == '\n') {
printf("\\n");
#ifndef _WIN32
/* On Unix, nothing else needs escaping */
} else {
putchar(c);
#else
/* On Windows, allow 7-bit printable characters to be displayed literally
and escape everything else (using the older \x notation for increased
compatibility, rather than the newer \U. */
} else if (c < 0x80 && iswprint(c)) {
putwchar(c);
} else {
printf("\\x%04x", c);
#endif
}
}

putchar('"');
}

#ifdef _WIN32
int wmain(int argc, wchar_t **argv)
#else
int main(int argc, char **argv)
#endif
{
if (argc == 3 && !strcmp_os(argv[1], T("encode-C-literal"))) {
encode_C_literal(argv[2]);
} else {
usage();
return 1;
}

return 0;
}
2 changes: 2 additions & 0 deletions runtime/startup_byt.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
#include "caml/startup_aux.h"
#include "caml/version.h"

#include "build_config.h"

#ifndef O_BINARY
#define O_BINARY 0
#endif
Expand Down

0 comments on commit 88676f6

Please sign in to comment.