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

CMake build and test. #303

Merged
merged 12 commits into from
Oct 11, 2017
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
**/.*.swp
**/.*.swo
**/*.o
**/*.a
**/*.dylib
*.dSYM

jsonnet
Expand All @@ -27,6 +29,21 @@ bazel-*
**/*.tfstate.backup

build/
external/
dist/
jsonnet.egg-info/

# Cmake
**/CMakeCache.txt
**/CMakeFiles
**/cmake_install.cmake
**/CTestTestfile.cmake
tags
bin/
Testing/

# Ignore auto-generated makefiles from CMake.
**/Makefile
^Makefile/

**/.DS_Store
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ before_install:
- echo $LC_ALL
before_script:
script:
- set -e
- rvm get head # Workaround 'shell_session_update: command not found'
- make test
- python setup.py build
- python setup.py test
# Test CMake build scripts.
- cmake . -Bbuild && cmake --build build --target run_tests
branches:
only:
- master
Expand Down
113 changes: 113 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Travis CI runs CMake 2.8.7 so we are pinned to that verison.
cmake_minimum_required(VERSION 2.8.7)
include(ExternalProject)

# User-configurable options.
option(BUILD_JSONNET "Build jsonnet command-line tool." ON)
option(BUILD_TESTS "Build and run jsonnet tests." ON)
set(GLOBAL_OUTPUT_PATH_SUFFIX "" CACHE STRING
"Output artifacts directory.")

project(jsonnet C CXX)

# Discourage in-source builds because they overwrite the hand-written Makefile.
# Use `cmake . -B<dir>` or the CMake GUI to do an out-of-source build.
if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR} AND
${CMAKE_GENERATOR} MATCHES "Makefile")
message(WARNING "In-source builds with the a makefile generator overwrite the handwritten Makefile. Out-of-source builds are recommended for this project.")
endif()

# Disable CMake >3.0 warnings on Mac OS.
set(CMAKE_MACOSX_RPATH 1)

# Set output paths.
set(GLOBAL_OUTPUT_PATH "${PROJECT_BINARY_DIR}/${GLOBAL_OUTPUT_PATH_SUFFIX}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${GLOBAL_OUTPUT_PATH})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${GLOBAL_OUTPUT_PATH})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${GLOBAL_OUTPUT_PATH})

# Include external googletest project. This runs a CMake sub-script
# (CMakeLists.txt.in) that downloads googletest source. It's then built as part
# of the jsonnet project. The conventional way of handling CMake dependencies is
# to use a find_package script, which finds and installs the library from
# known locations on the local machine. Downloading the library ourselves
# allows us to pin to a specific version and makes things easier for users
# who don't have package managers.
if (BUILD_TESTS)
enable_testing()

# Generate and download googletest project.
set(GOOGLETEST_DIR ${GLOBAL_OUTPUT_PATH}/googletest-download)
configure_file(CMakeLists.txt.in ${GOOGLETEST_DIR}/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${GOOGLETEST_DIR}
)
if(result)
message(FATAL_ERROR "googletest download failed: ${result}")
endif()

# Build googletest.
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${GOOGLETEST_DIR})
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()

# Prevent overriding the parent project's compiler/linker
# settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)

# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory(${GLOBAL_OUTPUT_PATH}/googletest-src
${GLOBAL_OUTPUT_PATH}/googletest-build)

# Include googletest headers.
include_directories("${gtest_SOURCE_DIR}/include")
endif()

# Compiler flags.
if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" OR
${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
set(OPT "-O3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -Wextra -pedantic -std=c99 -O3 ${OPT}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -Wextra -Woverloaded-virtual -pedantic -std=c++0x -fPIC ${OPT}")
else()
# TODO: Windows support.
message(FATAL_ERROR "Compiler ${CMAKE_CXX_COMPILER_ID} not supported")
endif()

# Look for libraries in global output path.
link_directories(${GLOBAL_OUTPUT_PATH})

# Targets

include_directories(
include
third_party/md5
core)

install(DIRECTORY include DESTINATION include)

add_subdirectory(stdlib)
add_subdirectory(third_party/md5)
add_subdirectory(core)
add_subdirectory(cmd)
add_subdirectory(test_suite)

if (BUILD_TESTS)
# Set JSONNET_CMD variable required for regression tests.
file(TO_NATIVE_PATH ${GLOBAL_OUTPUT_PATH}/jsonnet JSONNET_CMD)
set(CTEST_ENVIRONMENT
"JSONNET_CMD=${JSONNET_CMD}")

# s`run_tests` target builds and runs all tests. The cmake-generated `test`
# target runs tests without building them.
add_custom_target(run_tests COMMAND ${CMAKE_CTEST_COMMAND}
DEPENDS libjsonnet_test libjsonnet_test_file libjsonnet_test_snippet
jsonnet parser_test lexer_test
)

endif()
18 changes: 18 additions & 0 deletions CMakeLists.txt.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# CMake script run a generation-time. This must be separate from the main
# CMakeLists.txt file to allow downloading and building googletest at generation
# time.
cmake_minimum_required(VERSION 2.8.2)

project(googletest-download NONE)

include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
SOURCE_DIR "${GLOBAL_OUTPUT_PATH}/googletest-src"
BINARY_DIR "${GLOBAL_OUTPUT_PATH}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
2 changes: 2 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ git_repository(
new_git_repository(
name = "com_google_googletest",
remote = "https://github.com/google/googletest.git",

# If updating googletest version, also update CMakeLists.txt.in.
tag = "release-1.8.0",
build_file = "gmock.BUILD",
)
Expand Down
9 changes: 9 additions & 0 deletions cmd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Jsonnet command-line tool.

if (BUILD_JSONNET OR BUILD_TESTS)
add_executable(jsonnet ${LIBJSONNET_SOURCE} jsonnet.cpp)
add_dependencies(jsonnet libjsonnet_static)
target_link_libraries(jsonnet libjsonnet_static)

install(TARGETS jsonnet DESTINATION bin)
endif()
83 changes: 83 additions & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# libjsonnet

# Remember to update Bazel and Makefile builds when updating this list!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and MANIFEST.in and setup.py :(

set(LIBJSONNET_HEADERS
ast.h
desugarer.h
formatter.h
lexer.h
../include/libjsonnet.h
parser.h
pass.h
state.h
static_analysis.h
static_error.h
std.jsonnet.h
string_utils.h
unicode.h
vm.h)

set(LIBJSONNET_SOURCE
desugarer.cpp
formatter.cpp
lexer.cpp
libjsonnet.cpp
parser.cpp
pass.cpp
static_analysis.cpp
string_utils.cpp
vm.cpp)

add_library(libjsonnet SHARED ${LIBJSONNET_HEADERS} ${LIBJSONNET_SOURCE})
add_dependencies(libjsonnet md5 stdlib)
target_link_libraries(libjsonnet md5)

# CMake prepends CMAKE_SHARED_LIBRARY_PREFIX to shared libraries, so without
# this step the output would be |liblibjsonnet|.
set_target_properties(libjsonnet PROPERTIES OUTPUT_NAME jsonnet)
install(TARGETS libjsonnet DESTINATION lib)

# Static library for jsonnet command-line tool.
add_library(libjsonnet_static STATIC ${LIBJSONNET_SOURCE})
add_dependencies(libjsonnet_static md5)
target_link_libraries(libjsonnet_static md5)
set_target_properties(libjsonnet_static PROPERTIES OUTPUT_NAME jsonnet)

# Tests

function(add_test_executable test_name)
if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${test_name}.cpp)
set(TEST_EXT cpp)
else()
set(TEST_EXT c)
endif()
add_executable(${test_name} ${test_name}.${TEST_EXT})

add_dependencies(${test_name} libjsonnet_static gtest_main)
target_link_libraries(
${test_name} gtest gtest_main libjsonnet_static)
endfunction()

if (BUILD_TESTS)
add_test_executable(lexer_test)
add_test(lexer_test ${GLOBAL_OUTPUT_PATH}/lexer_test)

add_test_executable(parser_test)
add_test(parser_test ${GLOBAL_OUTPUT_PATH}/parser_test)

add_test_executable(libjsonnet_test)
add_test(libjsonnet_test ${GLOBAL_OUTPUT_PATH}/libjsonnet_test)

add_test_executable(libjsonnet_test_file)
add_test(libjsonnet_test_file
${GLOBAL_OUTPUT_PATH}/libjsonnet_test_file
${CMAKE_SOURCE_DIR}/test_suite/object.jsonnet)

set(TEST_SNIPPET "std.assertEqual(({ x: 1, y: self.x } { x: 2 }).y, 2)")
add_test_executable(libjsonnet_test_snippet)
add_test(libjsonnet_test_snippet
${GLOBAL_OUTPUT_PATH}/libjsonnet_test_snippet ${TEST_SNIPPET})

add_test(jsonnet_test_snippet
${GLOBAL_OUTPUT_PATH}/jsonnet -e ${TEST_SNIPPET})
endif()
5 changes: 5 additions & 0 deletions include/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
set(LIB_HEADER
${LIB_HEADER}
${CMAKE_CURRENT_SOURCE_DIR}/libjsonnet.h
${CMAKE_CURRENT_SOURCE_DIR}/libjsonnet++.h
PARENT_SCOPE)
15 changes: 15 additions & 0 deletions stdlib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Utility to convert file to a list of integeters.

add_executable(to_c_array to_c_array.cpp)

# Custom command that will only build stdlib when it changes.
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/core/std.jsonnet.h
COMMAND ${GLOBAL_OUTPUT_PATH}/to_c_array
${PROJECT_SOURCE_DIR}/stdlib/std.jsonnet
${PROJECT_SOURCE_DIR}/core/std.jsonnet.h
DEPENDS to_c_array std.jsonnet)

# Standard library build target that libjsonnet can depend on.
add_custom_target(stdlib ALL
DEPENDS ${PROJECT_SOURCE_DIR}/core/std.jsonnet.h)
41 changes: 41 additions & 0 deletions stdlib/to_c_array.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Converts stdin string to a comma-separated list of byte values and prints the
// result. Used for transforming the standard library into a C array.
//
// Usage:
// to_c_array <infile> <outfile>
#include <fstream>
#include <iostream>
#include <iterator>

int main(int argc, char *argv[]) {
if (argc < 3) {
std::cerr << "usage: to_c_array <infile> <outfile>\n";
return 1;
}

std::ifstream in_file(argv[1]);
if (!in_file.is_open()) {
std::cerr << "Can't open input file.";
return 1;
}

std::ofstream out_file(argv[2]);
if (!out_file.is_open()) {
std::cerr << "Can't open output file.";
return 1;
}

char c;
bool first_character = true;
while (in_file.get(c)) {
if (first_character) {
first_character = false;
} else {
out_file << ",";
}
// Write byte value of c to stdout.
out_file << (int)c;
}

return 0;
}
11 changes: 11 additions & 0 deletions test_suite/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
find_program(BASH bash)
if (BASH STREQUAL "BASH-NOTFOUND")
message(WARNING "Bash not found, can't run regression tests.")
else()
# Note: this test relies on the JSONNET_CMD environment variable, which
# is set in the root CMakeLists.txt.
add_test(
NAME regression_test
COMMAND ${BASH} ${CMAKE_CURRENT_SOURCE_DIR}/run_tests.sh
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
1 change: 1 addition & 0 deletions third_party/md5/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_library(md5 STATIC md5.cpp md5.h)