[build] move to ctypes stubs

Summary:
This removes the dependency of libffi, and gives better guarantees at
compile-time. A bit overkill to retrieve the width of the terminal but what do
you know...

Reviewed By: jberdine

Differential Revision: D4700003

fbshipit-source-id: 036989b
master
Jules Villard 8 years ago committed by Facebook Github Bot
parent 0548b7bd5e
commit 0b4f4953a5

1
.gitignore vendored

@ -102,6 +102,7 @@ buck-out/
/scripts/checkCopyright /scripts/checkCopyright
/infer/etc/clang_ast.dict /infer/etc/clang_ast.dict
/infer/src/toplevel.mlpack /infer/src/toplevel.mlpack
/infer/src/ffi/gen/*.ml
#atdgen stubs #atdgen stubs
/infer/src/backend/jsonbug_* /infer/src/backend/jsonbug_*

@ -21,7 +21,6 @@ compile everything from source (see the end of this document).
- opam 1.2.2 (instructions [here](https://opam.ocaml.org/doc/Install.html#OSX)) - opam 1.2.2 (instructions [here](https://opam.ocaml.org/doc/Install.html#OSX))
- Python 2.7 - Python 2.7
- pkg-config - pkg-config
- libffi >= 3.0
- Java (only needed for the Java analysis) - Java (only needed for the Java analysis)
- cmake (only needed for the C/Objective-C analysis) - cmake (only needed for the C/Objective-C analysis)
- clang in Xcode command line tools. You can install them with the command - clang in Xcode command line tools. You can install them with the command
@ -33,7 +32,7 @@ You can install some of these dependencies using
[Homebrew](http://brew.sh/): [Homebrew](http://brew.sh/):
```sh ```sh
brew install autoconf automake cmake libffi opam pkg-config brew install autoconf automake cmake opam pkg-config
brew install caskroom/cask/brew-cask brew install caskroom/cask/brew-cask
brew cask install java brew cask install java
``` ```
@ -49,7 +48,6 @@ compile everything from source (see the end of this document).
- opam 1.2.2 - opam 1.2.2
- Python 2.7 - Python 2.7
- pkg-config - pkg-config
- libffi >= 3.0
- Java (only needed for the Java analysis) - Java (only needed for the Java analysis)
- gcc >= 4.7.2 or clang >= 3.1 (only needed for the C/Objective-C analysis) - gcc >= 4.7.2 or clang >= 3.1 (only needed for the C/Objective-C analysis)
- autoconf >= 2.63 and automake >= 1.11.1 (if building from git) - autoconf >= 2.63 and automake >= 1.11.1 (if building from git)
@ -114,7 +112,6 @@ sudo apt-get install -y \
automake \ automake \
build-essential \ build-essential \
git \ git \
libffi-dev \
libgmp-dev \ libgmp-dev \
libmpc-dev \ libmpc-dev \
libmpfr-dev \ libmpfr-dev \
@ -134,7 +131,6 @@ sudo apt install -y \
automake \ automake \
build-essential \ build-essential \
git \ git \
libffi-dev \
libgmp-dev \ libgmp-dev \
libmpc-dev \ libmpc-dev \
libmpfr-dev \ libmpfr-dev \
@ -163,7 +159,6 @@ sudo apt-get install -y \
g++-4.8 \ g++-4.8 \
gcc-4.8 \ gcc-4.8 \
git \ git \
libffi-dev \
libgmp-dev \ libgmp-dev \
libmpc-dev \ libmpc-dev \
libmpfr-dev \ libmpfr-dev \

@ -155,11 +155,12 @@ test_build: clang_plugin
ifeq ($(IS_FACEBOOK_TREE),yes) ifeq ($(IS_FACEBOOK_TREE),yes)
@$(MAKE) -C facebook setup @$(MAKE) -C facebook setup
endif endif
@$(MAKE) -C $(SRC_DIR) test_build @$(MAKE) -C $(SRC_DIR) TEST=1 byte
@$(MAKE) -C $(SRC_DIR) TEST=1 toplevel
.PHONY: ocaml_unit_test .PHONY: ocaml_unit_test
ocaml_unit_test: test_build ocaml_unit_test: test_build
$(call silent_on_success,$(TEST_BUILD_DIR)/unit/inferunit.byte) $(call silent_on_success,$(BUILD_DIR)/test/infer/unit/inferunit.byte)
DIRECT_TESTS_REPLACE = $(patsubst %_frontend,%_frontend_replace,$(filter %_frontend,$(DIRECT_TESTS))) DIRECT_TESTS_REPLACE = $(patsubst %_frontend,%_frontend_replace,$(filter %_frontend,$(DIRECT_TESTS)))

@ -47,6 +47,7 @@ MVN = @MVN@
NCPU = @NCPU@ NCPU = @NCPU@
NDKBUILD = @NDKBUILD@ NDKBUILD = @NDKBUILD@
OCAMLC = @OCAMLC@ OCAMLC = @OCAMLC@
OCAMLFIND = @OCAMLFIND@
OCAMLLEX = @OCAMLLEX@ OCAMLLEX = @OCAMLLEX@
OCAMLOPT = @OCAMLOPT@ OCAMLOPT = @OCAMLOPT@
prefix = @prefix@ prefix = @prefix@

@ -42,8 +42,6 @@ JAVA_MODELS_DIR = $(MODELS_DIR)/java/src
SRC_DIR = $(INFER_DIR)/src SRC_DIR = $(INFER_DIR)/src
BUILD_DIR = $(INFER_DIR)/_build BUILD_DIR = $(INFER_DIR)/_build
INFER_BUILD_DIR = $(BUILD_DIR)/infer
TEST_BUILD_DIR = $(BUILD_DIR)/test
JAVA_LIB_DIR = $(LIB_DIR)/java JAVA_LIB_DIR = $(LIB_DIR)/java
SPECS_LIB_DIR = $(LIB_DIR)/specs SPECS_LIB_DIR = $(LIB_DIR)/specs

@ -11,6 +11,13 @@ include $(ROOT_DIR)/Makefile.config
#### Global declarations #### #### Global declarations ####
ETC_DIR = $(INFER_DIR)/etc ETC_DIR = $(INFER_DIR)/etc
ifeq ($(TEST),1)
BASE_BUILD_DIR = $(BUILD_DIR)/test
else
BASE_BUILD_DIR = $(BUILD_DIR)
endif
STUBS_BUILD_DIR = $(BASE_BUILD_DIR)/stubs
INFER_BUILD_DIR = $(BASE_BUILD_DIR)/infer
ATDGEN_SUFFIXES = _t.ml _t.mli _j.ml _j.mli ATDGEN_SUFFIXES = _t.ml _t.mli _j.ml _j.mli
@ -24,7 +31,6 @@ OCAMLBUILD_OPTIONS = \
-r \ -r \
-use-menhir -menhir '$(MENHIR) --explain --strict'\ -use-menhir -menhir '$(MENHIR) --explain --strict'\
-use-ocamlfind \ -use-ocamlfind \
-lflags -cclib,-lffi \
-cflags -g -lflags -g \ -cflags -g -lflags -g \
-cflags -short-paths \ -cflags -short-paths \
-cflags -safe-string \ -cflags -safe-string \
@ -32,10 +38,10 @@ OCAMLBUILD_OPTIONS = \
-cflags -strict-formats \ -cflags -strict-formats \
-cflags -strict-sequence \ -cflags -strict-sequence \
-cflags -w,$(OCAML_FATAL_WARNINGS)-4-9-32-40-41-42-45-48 \ -cflags -w,$(OCAML_FATAL_WARNINGS)-4-9-32-40-41-42-45-48 \
-tag-line "<*{clang/clang_ast_*,backend/jsonbug_*,checkers/stacktree_*}>: warn(-27-32-35-39)" \ -tag-line "<*{clang/clang_ast_*,backend/jsonbug_*,checkers/stacktree_*,ffi/gen/*}>: warn(-27-32-34-35-39)" \
-tag-line "<*/{,*/}*.{ml,re}{,i}>: package(ppx_compare)" \ -tag-line "<*/{,*/}*.{ml,re}{,i}>: package(ppx_compare)" \
-tag thread \ -tag thread \
-pkgs atdgen,core,ctypes.foreign,extlib,oUnit,str,unix,xmlm,yojson,zip -pkgs atdgen,core,ctypes.stubs,extlib,oUnit,str,unix,xmlm,yojson,zip
ifeq ($(ENABLE_OCAML_BINANNOT),yes) ifeq ($(ENABLE_OCAML_BINANNOT),yes)
OCAMLBUILD_OPTIONS += -cflags -bin-annot OCAMLBUILD_OPTIONS += -cflags -bin-annot
@ -49,6 +55,10 @@ ifneq (,$(findstring s,$(MAKEFLAGS)))
OCAMLBUILD_OPTIONS += -quiet OCAMLBUILD_OPTIONS += -quiet
endif endif
ifeq ($(TEST),1)
OCAMLBUILD_OPTIONS += -cflags -warn-error,$(OCAML_FATAL_WARNINGS)
endif
#### Backend declarations #### #### Backend declarations ####
@ -121,10 +131,16 @@ else
EXTRA_DEPS = opensource EXTRA_DEPS = opensource
endif endif
DEPENDENCIES = IR backend base checkers eradicate harness integration quandary bufferoverrun $(EXTRA_DEPS) DEPENDENCIES = \
IR backend base checkers eradicate ffi ffi/gen harness integration quandary bufferoverrun \
$(EXTRA_DEPS)
# ocamlbuild command with options common to all build targets # ocamlbuild command with options common to all build targets
OCAMLBUILD_BASE = $(REBUILD) $(OCAMLBUILD_OPTIONS) -j $(NCPU) $(addprefix -I , $(DEPENDENCIES)) OCAMLBUILD_BASE = \
$(REBUILD) $(OCAMLBUILD_OPTIONS) -j $(NCPU) $(addprefix -I , $(DEPENDENCIES)) \
OCAMLBUILD_EXTRA_BYTE = -lflags -custom,$(INFER_BUILD_DIR)/ffi/gen/extern_stubs.o
OCAMLBUILD_EXTRA_NATIVE = -lflag $(INFER_BUILD_DIR)/ffi/gen/extern_stubs.o
# ocamlbuild with options necessary to build all targets at once, regardless of configure flags # ocamlbuild with options necessary to build all targets at once, regardless of configure flags
OCAMLBUILD_ALL = $(OCAMLBUILD_BASE) $(JAVA_OCAMLBUILD_OPTIONS) OCAMLBUILD_ALL = $(OCAMLBUILD_BASE) $(JAVA_OCAMLBUILD_OPTIONS)
@ -154,6 +170,9 @@ DEPENDENCIES += clang unit/clang
else else
DEPENDENCIES += unit/clang_stubs DEPENDENCIES += unit/clang_stubs
endif endif
ifeq ($(TEST),1)
INFER_CONFIG_TARGETS += $(INFERUNIT_MAIN).native
endif
OCAML_BASE_SOURCES = \ OCAML_BASE_SOURCES = \
$(wildcard $(DEPENDENCIES:=/[a-zA-Z]*.ml) $(DEPENDENCIES:=/[a-zA-Z]*.mli) \ $(wildcard $(DEPENDENCIES:=/[a-zA-Z]*.ml) $(DEPENDENCIES:=/[a-zA-Z]*.mli) \
@ -171,11 +190,43 @@ export OCAMLFIND_IGNORE_DUPS_IN=$(shell $(OCAMLC) -where)/compiler-libs
.PHONY: all .PHONY: all
all: infer all: infer
# witness that generators have been built
STUBS_HAVE_BEEN_BUILT = $(INFER_BUILD_DIR)/ffi/gen/generate_caml_types.c
# witness that generators have been run
STUBS_HAVE_RUN = ffi/gen/IOCtl_types.ml
# to make sure everything Cstubs-related has been done
STUBS_DEPS = $(STUBS_HAVE_RUN) $(INFER_BUILD_DIR)/ffi/gen/extern_stubs.o
$(STUBS_HAVE_BEEN_BUILT): $(wildcard ffi/*.ml) $(MAKEFILE_LIST)
$(MKDIR_P) $(BASE_BUILD_DIR) $(@D)
$(OCAMLBUILD_CONFIG) -build-dir $(STUBS_BUILD_DIR) \
ffi/GenerateML.native ffi/GenerateC.native ffi/GenerateCGenerator.native
$(STUBS_BUILD_DIR)/ffi/GenerateML.native > ffi/gen/ExternStubs.ml
$(STUBS_BUILD_DIR)/ffi/GenerateC.native > $(@D)/extern_stubs.c
$(STUBS_BUILD_DIR)/ffi/GenerateCGenerator.native > $(@D)/generate_caml_types.c
@touch $@
$(STUBS_HAVE_RUN): $(STUBS_HAVE_BEEN_BUILT) $(MAKEFILE_LIST)
# create .o file using the right flags, which ocamlfind knows about
cd $(INFER_BUILD_DIR)/$(@D) && \
$(OCAMLFIND) ocamlc -package ctypes.stubs generate_caml_types.c
# link the executable by calling CC directly (no idea how to do it with ocaml*)
cd $(INFER_BUILD_DIR)/$(@D) && \
$(CC) generate_caml_types.o -o generate_caml_types
$(INFER_BUILD_DIR)/$(@D)/generate_caml_types > $@
@touch $@
$(INFER_BUILD_DIR)/ffi/gen/extern_stubs.o: $(STUBS_HAVE_BEEN_BUILT)
cd $(@D) && $(OCAMLFIND) ocamlc -package ctypes.stubs extern_stubs.c
@touch $@
# single out infer.native as the source of truth for make, knowing that in fact several targets are # single out infer.native as the source of truth for make, knowing that in fact several targets are
# produced by the build # produced by the build
$(INFER_BUILD_DIR)/$(INFER_MAIN).native: base/Version.ml $(BUILD_DIR) $(OCAML_CONFIG_SOURCES) \ $(INFER_BUILD_DIR)/$(INFER_MAIN).native: base/Version.ml $(OCAML_CONFIG_SOURCES) \
$(MAKEFILE_LIST) $(STUBS_DEPS) $(MAKEFILE_LIST)
$(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) $(INFER_CONFIG_TARGETS) $(MKDIR_P) $(BASE_BUILD_DIR)
$(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) $(OCAMLBUILD_EXTRA_NATIVE) \
$(INFER_CONFIG_TARGETS)
# let make know that the target is up-to-date even if ocamlbuild cached it # let make know that the target is up-to-date even if ocamlbuild cached it
@touch $@ @touch $@
@ -199,8 +250,9 @@ ifeq ($(BUILD_C_ANALYZERS),yes)
infer: $(CLANG_BINIOU_DICT) infer: $(CLANG_BINIOU_DICT)
endif endif
$(INFER_BUILD_DIR)/$(INFER_MAIN).byte: base/Version.ml $(BUILD_DIR) $(OCAML_CONFIG_SOURCES) $(INFER_BUILD_DIR)/$(INFER_MAIN).byte: base/Version.ml $(STUBS_DEPS) $(OCAML_CONFIG_SOURCES)
$(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) \ $(MKDIR_P) $(BASE_BUILD_DIR)
$(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) $(OCAMLBUILD_EXTRA_BYTE) \
$(INFER_CONFIG_TARGETS:.native=.byte) $(INFERUNIT_MAIN).byte $(INFER_CONFIG_TARGETS:.native=.byte) $(INFERUNIT_MAIN).byte
@touch $@ @touch $@
@ -225,21 +277,12 @@ M=
MFLAGS= MFLAGS=
.PHONY: module .PHONY: module
module: base/Version.ml $(BUILD_DIR) $(OCAML_ALL_SOURCES) module: base/Version.ml $(OCAML_ALL_SOURCES)
$(OCAMLBUILD_ALL) -build-dir $(INFER_BUILD_DIR) \ $(MKDIR_P) $(BASE_BUILD_DIR)
$(OCAMLBUILD_ALL) -build-dir $(INFER_BUILD_DIR) $(OCAMLBUILD_EXTRA_BYTE) \
$(MFLAGS) \ $(MFLAGS) \
$(M) $(M)
$(TEST_BUILD_DIR)/$(INFER_MAIN).byte: base/Version.ml $(BUILD_DIR) $(OCAML_CONFIG_SOURCES) \
toplevel.mlpack $(MAKEFILE_LIST)
$(OCAMLBUILD_CONFIG) -build-dir $(TEST_BUILD_DIR) \
-cflags -warn-error,$(OCAML_FATAL_WARNINGS) \
$(INFER_CONFIG_TARGETS:.native=.byte) $(INFERUNIT_MAIN).byte toplevel.cmo
@touch $@
.PHONY: test_build
test_build: $(TEST_BUILD_DIR)/$(INFER_MAIN).byte
# to generate interface file.mli from implementation file.ml execute: # to generate interface file.mli from implementation file.ml execute:
# make M=file mli # make M=file mli
mli: mli:
@ -285,7 +328,7 @@ $(shell \
| awk 'BEGIN { FS = "/"; OFS = "/" } ; {$$NF=toupper(substr($$NF,1,1))substr($$NF,2); print $$0}') | awk 'BEGIN { FS = "/"; OFS = "/" } ; {$$NF=toupper(substr($$NF,1,1))substr($$NF,2); print $$0}')
endef endef
toplevel.mlpack: base/Version.ml $(OCAML_CONFIG_SOURCES) $(MAKEFILE_LIST) toplevel.mlpack: base/Version.ml $(STUBS_DEPS) $(OCAML_CONFIG_SOURCES) $(MAKEFILE_LIST)
# We need to pack all the infer modules into another module to avoid name clashes with some # We need to pack all the infer modules into another module to avoid name clashes with some
# of them coming from ocaml libraries (Ident for example). To do that, we generate a .mlpack # of them coming from ocaml libraries (Ident for example). To do that, we generate a .mlpack
# file containing namespaced modules. # file containing namespaced modules.
@ -297,13 +340,16 @@ toplevel.mlpack: base/Version.ml $(OCAML_CONFIG_SOURCES) $(MAKEFILE_LIST)
$(foreach module,\ $(foreach module,\
$(filter-out $(foreach root,$(roots),%/$(root)),\ $(filter-out $(foreach root,$(roots),%/$(root)),\
$(foreach source,\ $(foreach source,\
$(filter-out unit/%,$(OCAML_CONFIG_SOURCES)),\ $(filter-out unit/% ffi/%,$(OCAML_CONFIG_SOURCES)),\
$(call to_ocaml_module,$(source)))),\ $(call to_ocaml_module,$(source)))),\
$(shell echo $(module) >> $($@_tmp))) $(shell echo $(module) >> $($@_tmp)))
mv $($@_tmp) $@ mv $($@_tmp) $@
$(INFER_BUILD_DIR)/toplevel.cmo: toplevel.mlpack $(BUILD_DIR) $(INFER_BUILD_DIR)/toplevel.cmo: toplevel.mlpack
$(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) toplevel.cmo $(MKDIR_P) $(BASE_BUILD_DIR)
$(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) $(OCAMLBUILD_EXTRA_BYTE) toplevel.cmo
cd $(INFER_BUILD_DIR)/ffi/gen && \
ocamlmklib -o externstubslib ExternStubs.cmo extern_stubs.o
@touch $@ @touch $@
.PHONY: toplevel .PHONY: toplevel
@ -312,12 +358,13 @@ toplevel: $(INFER_BUILD_DIR)/toplevel.cmo
.PHONY: checkCopyright .PHONY: checkCopyright
checkCopyright: $(CHECKCOPYRIGHT_BIN) checkCopyright: $(CHECKCOPYRIGHT_BIN)
$(CHECKCOPYRIGHT_BIN): $(BUILD_DIR) $(CHECKCOPYRIGHT_MAIN).ml Makefile $(CHECKCOPYRIGHT_BIN): $(CHECKCOPYRIGHT_MAIN).ml $(MAKEFILE_LIST)
$(REBUILD) -quiet -r -j $(NCPU) -build-dir $(BUILD_DIR)/checkCopyright \ $(MKDIR_P) $(BASE_BUILD_DIR)
$(REBUILD) -quiet -r -j $(NCPU) -build-dir $(BASE_BUILD_DIR)/checkCopyright \
-cflags -g,-safe-string -lflags -g \ -cflags -g,-safe-string -lflags -g \
-pkgs core,str -tag thread -use-ocamlfind $(CHECKCOPYRIGHT_MAIN).native -pkgs core,str -tag thread -use-ocamlfind $(CHECKCOPYRIGHT_MAIN).native
$(INSTALL_PROGRAM) \ $(INSTALL_PROGRAM) \
$(BUILD_DIR)/checkCopyright/$(CHECKCOPYRIGHT_MAIN).native $(CHECKCOPYRIGHT_BIN) $(BASE_BUILD_DIR)/checkCopyright/$(CHECKCOPYRIGHT_MAIN).native $(CHECKCOPYRIGHT_BIN)
define gen_atdgen_rules define gen_atdgen_rules
# generate files using atdgen # generate files using atdgen
@ -382,13 +429,6 @@ base/Version.ml: base/Version.ml.in $(MAKEFILE_LIST)
cat "$$TMPFILE" > $@; \ cat "$$TMPFILE" > $@; \
$(REMOVE) "$$TMPFILE" $(REMOVE) "$$TMPFILE"
$(BUILD_DIR):
$(MKDIR_P) $(BUILD_DIR)
.PHONY: test_clean
test_clean:
$(REMOVE_DIR) $(TEST_BUILD_DIR)
.PHONY: clean .PHONY: clean
clean: clean:
$(REMOVE) $(INFER_ALL_TARGETS) $(REMOVE) $(INFER_ALL_TARGETS)
@ -405,3 +445,4 @@ clean:
$(REMOVE) $(INFER_CLANG_FCP_MIRRORED_FILES) $(REMOVE) $(INFER_CLANG_FCP_MIRRORED_FILES)
$(REMOVE) mod_dep.dot $(REMOVE) mod_dep.dot
$(REMOVE) mod_dep.pdf $(REMOVE) mod_dep.pdf
$(REMOVE) ffi/gen/*

@ -16,6 +16,19 @@ module YBU = Yojson.Basic.Util
let (=) = String.equal let (=) = String.equal
let terminal_width = lazy (
let open Ctypes in
let module T = IOCtl.Types(IOCtl_types) in
let winsize = make IOCtl.winsize in
let return =
ExternStubs.ioctl_stub_1_ioctl 0 T.Request.request_TIOCGWINSZ
(ExternStubs.CI.cptr (addr winsize)) in
if return >= 0 then
Ok (Unsigned.UShort.to_int (getf winsize IOCtl.ws_col))
else
Error return
)
(** This is the subset of Arg.spec that we actually use. What's important is that all these specs (** This is the subset of Arg.spec that we actually use. What's important is that all these specs
call back functions. We use this to mark deprecated arguments. What's not important is that, eg, call back functions. We use this to mark deprecated arguments. What's not important is that, eg,
Arg.Float is missing. *) Arg.Float is missing. *)
@ -200,7 +213,7 @@ let pad_and_xform doc_width left_width desc =
let align desc_list = let align desc_list =
let min_term_width = 80 in let min_term_width = 80 in
let cur_term_width = let cur_term_width =
match Lazy.force IOCtl.terminal_width with match Lazy.force terminal_width with
| Ok width -> width | Ok width -> width
| Error _ -> min_term_width in | Error _ -> min_term_width in
(* 2 blank columns before option + 2 columns of gap between flag and doc *) (* 2 blank columns before option + 2 columns of gap between flag and doc *)

@ -1,16 +1,12 @@
(* (*
* Copyright (c) 2016 - present Facebook, Inc. * Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD style license found in the * This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*) *)
(** bindings to ioctl(2) that only capture what we need *)
open! IStd open! IStd
open Ctypes open Ctypes
type winsize type winsize
@ -22,22 +18,17 @@ let ws_xpixel = field winsize "ws_xpixel" ushort
let ws_ypixel = field winsize "ws_ypixel" ushort let ws_ypixel = field winsize "ws_ypixel" ushort
let () = seal winsize let () = seal winsize
(* as found in asm-generic/ioctls.h *) module Types (F: Cstubs.Types.TYPE) = struct
let request_TIOCGWINSZ = Unsigned.ULong.of_int 0x5413 module Request = struct
let request_TIOCGWINSZ = F.constant "TIOCGWINSZ" F.ulong
end
end
(* ioctl(2) is a variadic function, so cross our fingers that the calling convention works the same module Bindings (F : Cstubs.FOREIGN) = struct
as non-variadic functions and define different ioctl_* functions for each need *) let (@->) = F.(@->) (* shadow Ctypes' operator *)
let ioctl_winsize = (* ioctl(2) is a variadic function, so cross our fingers that the calling convention works the
Foreign.foreign "ioctl" same as non-variadic functions and define different ioctl_* functions for each need *)
(int @-> ulong @-> ptr winsize @-> returning int)
(** high-level function *) let ioctl_winsize = F.foreign "ioctl" (int @-> ulong @-> ptr winsize @-> F.returning int)
let terminal_width = lazy( end
let winsize = make winsize in
let return = ioctl_winsize 0 request_TIOCGWINSZ (addr winsize) in
if return >= 0 then
Ok (Unsigned.UShort.to_int (getf winsize ws_col))
else
Error return
)

@ -9,6 +9,24 @@
(** bindings to ioctl(2) that only capture what we need *) (** bindings to ioctl(2) that only capture what we need *)
open! IStd open! IStd
open Ctypes
type winsize
val winsize : winsize structure typ
val ws_col : (Unsigned.ushort, winsize structure) field
val ws_row : (Unsigned.ushort, winsize structure) field
val ws_xpixel : (Unsigned.ushort, winsize structure) field
val ws_ypixel : (Unsigned.ushort, winsize structure) field
module Types : functor (F : Cstubs.Types.TYPE) -> sig
module Request : sig val request_TIOCGWINSZ : Unsigned.ulong F.const end
end
val terminal_width : (int, int) Result.t lazy_t module Bindings : functor (F : Cstubs.FOREIGN) -> sig
val ioctl_winsize :
(int ->
Unsigned.ulong -> winsize structure Ctypes_static.ptr -> int F.return)
F.result
end

@ -0,0 +1,11 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
let () =
print_endline "#include <sys/ioctl.h>";
Cstubs.write_c Format.std_formatter ~prefix:GenerateUtils.prefix (module IOCtl.Bindings)

@ -0,0 +1,11 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
let () =
print_endline "#include <sys/ioctl.h>";
Cstubs.Types.write_c Format.std_formatter (module IOCtl.Types)

@ -0,0 +1,10 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
let () =
Cstubs.write_ml Format.std_formatter ~prefix:GenerateUtils.prefix (module IOCtl.Bindings)

@ -0,0 +1,12 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
(* Utility module common for other Generate* modules. *)
let prefix = "ioctl_stub"

@ -0,0 +1,12 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
(* Utility module common for other Generate* modules. *)
val prefix : string

@ -30,7 +30,6 @@ depends: [
"core" {>="113.33.03"} "core" {>="113.33.03"}
"conf-autoconf" "conf-autoconf"
"ctypes" {>="0.9.2"} "ctypes" {>="0.9.2"}
"ctypes-foreign" {>="0.4.0"}
"extlib-compat" "extlib-compat"
"javalib" {>="2.3.3"} "javalib" {>="2.3.3"}
"ocamlfind" {build} "ocamlfind" {build}

@ -6,7 +6,12 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# toplevel (`make toplevel`) they get the expected version of infer. The _build/test toplevel is # toplevel (`make toplevel`) they get the expected version of infer. The _build/test toplevel is
# built during `make test` which is probably run less often, hence why it doesn't take # built during `make test` which is probably run less often, hence why it doesn't take
# precedence. Of course this cannot be perfect so caution is advised. # precedence. Of course this cannot be perfect so caution is advised.
TOPLEVEL_INCLUDES="-I $SCRIPT_DIR/../infer/_build/infer -I $SCRIPT_DIR/../infer/_build/test" TOPLEVEL_INCLUDES=(
-I "$SCRIPT_DIR"/../infer/_build/infer
-I "$SCRIPT_DIR"/../infer/_build/infer/ffi/gen
-I "$SCRIPT_DIR"/../infer/_build/test/infer
-I "$SCRIPT_DIR"/../infer/_build/test/infer/ffi/gen
)
# to build new toplevel, run `make toplevel` # to build new toplevel, run `make toplevel`
# -init option is used only in interactive mode # -init option is used only in interactive mode
@ -22,4 +27,4 @@ TOPLEVEL_INCLUDES="-I $SCRIPT_DIR/../infer/_build/infer -I $SCRIPT_DIR/../infer/
if [ -z "$INFER_REPL_BINARY" ]; then if [ -z "$INFER_REPL_BINARY" ]; then
INFER_REPL_BINARY="utop" INFER_REPL_BINARY="utop"
fi fi
$INFER_REPL_BINARY -init $SCRIPT_DIR/toplevel_init $TOPLEVEL_INCLUDES -I $SCRIPT_DIR $@ $INFER_REPL_BINARY -init $SCRIPT_DIR/toplevel_init ${TOPLEVEL_INCLUDES[@]} -I $SCRIPT_DIR $@

@ -1,13 +1,14 @@
(* load dependencies *) (* load dependencies *)
#use "topfind";; #use "topfind";;
#thread;; #thread;;
#require "core";; #require "core.top";;
#require "ctypes";; #require "ctypes";;
#require "ctypes.foreign";; #require "ctypes.stubs";;
#require "sawja";; #require "sawja";;
#require "atdgen";; #require "atdgen";;
#require "xmlm";; #require "xmlm";;
(* load infer code *) (* load infer code *)
#load "externstubslib.cma";;
#load_rec "toplevel.cmo";; #load_rec "toplevel.cmo";;
open Toplevel;; open Toplevel;;

Loading…
Cancel
Save