Skip to content

Commit

Permalink
Add lemon/3.32.3 recipe (#2201)
Browse files Browse the repository at this point in the history
* Add lemon/3.32.3 recipe

* lemon: gcc accepts int main(int argc, char *argv)...

* lemon: add patch to search for templates in bindir

* lemon: strip executable name from string

* lemon: check for error using GetLastError

* lemon: MAX_PATH is only known on Windows

* lemon: aliase build_type and compiler

* lemon: remove unused function

* lemon: avoid ci building debug packages

* lemon: only build test_package when not cross building
  • Loading branch information
madebr authored Aug 12, 2020
1 parent 2b0b565 commit 60bc873
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 0 deletions.
9 changes: 9 additions & 0 deletions recipes/lemon/all/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 2.8.14)
project(ConanLemon C)

include(conanbuildinfo.cmake)
conan_basic_setup()

add_executable(lemon source_subfolder/tool/lemon.c)
install(TARGETS lemon RUNTIME DESTINATION bin)
install(FILES source_subfolder/tool/lempar.c DESTINATION bin)
8 changes: 8 additions & 0 deletions recipes/lemon/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
sources:
"3.32.3":
"url": "https://sqlite.org/2020/sqlite-src-3320300.zip"
"sha256": "9312f0865d3692384d466048f746d18f88e7ffd1758b77d4f07904e03ed5f5b9"
patches:
"3.32.3":
- patch_file: "patches/0001-use-executable-template-path.patch"
base_path: "source_subfolder"
58 changes: 58 additions & 0 deletions recipes/lemon/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import os
from conans import CMake, ConanFile, tools


class LemonConan(ConanFile):
name = "lemon"
description = "The Lemon program reads a grammar of the input language and emits C-code to implement a parser for that language."
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://sqlite.org/lemon.html"
topics = ("conan", "lemon", "grammar", "lexer", "lalr", "parser", "generator", "sqlite")
license = "Public Domain"
exports_sources = "CMakeLists.txt", "patches/**"
settings = "os", "compiler", "arch", "build_type"
generators = "cmake"

@property
def _source_subfolder(self):
return "source_subfolder"

_cmake = None

def configure(self):
del self.settings.compiler.libcxx
del self.settings.compiler.cppstd

def source(self):
tools.get(**self.conan_data["sources"][self.version])
url = self.conan_data["sources"][self.version]["url"]
archive_name = os.path.basename(url)
archive_name = os.path.splitext(archive_name)[0]
os.rename(archive_name, self._source_subfolder)

def _configure_cmake(self):
if self._cmake:
return self._cmake
self._cmake = CMake(self)
self._cmake.configure()
return self._cmake

def build(self):
for patch in self.conan_data.get("patches", {}).get(self.version, []):
tools.patch(**patch)
cmake = self._configure_cmake()
cmake.build()

def _extract_license_text(self):
header = tools.load(os.path.join(self._source_subfolder, "tool", "lempar.c"))
return "\n".join(line.strip(" \n*") for line in header[3:header.find("*******", 1)].splitlines())

def package(self):
tools.save(os.path.join(self.package_folder, "licenses", "LICENSE"), self._extract_license_text())
cmake = self._configure_cmake()
cmake.install()

def package_info(self):
bin_path = os.path.join(self.package_folder, "bin")
self.output.info("Appending PATH environment variable: {}".format(bin_path))
self.env_info.PATH.append(bin_path)
65 changes: 65 additions & 0 deletions recipes/lemon/all/patches/0001-use-executable-template-path.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
--- tool/lemon.c
+++ tool/lemon.c
@@ -3502,11 +3502,53 @@
}
}

+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#else
+# include <libgen.h>
+# include <unistd.h>
+#endif
+#include <string.h>
+
+#define DEFAULT_PATH "."
+
+static char *get_default_template_path(const char *filename) {
+ static char static_path[8192];
+#ifdef _WIN32
+# define JOINER "\\"
+ SetLastError(ERROR_SUCCESS);
+ int result = GetModuleFileNameA(NULL, static_path, sizeof(static_path));
+ if (GetLastError() != ERROR_SUCCESS) {
+ memcpy(static_path, DEFAULT_PATH, strlen(DEFAULT_PATH));
+ }
+ char *pos = strrchr(static_path, '\\');
+ if (pos) {
+ *pos = '\0';
+ }
+#else
+# define JOINER "/"
+ ssize_t nb = readlink("/proc/self/exe", static_path, sizeof(static_path));
+ if (nb != -1) {
+ static_path[nb] = '\0';
+ dirname(static_path);
+ } else {
+ memcpy(static_path, DEFAULT_PATH, strlen(DEFAULT_PATH));
+ }
+#endif
+ if (sizeof(static_path) < (strlen(static_path) + sizeof(JOINER) + strlen(filename) + 1)) {
+ strcpy(static_path, DEFAULT_PATH);
+ }
+ strncat(static_path, JOINER, sizeof(JOINER));
+ strncat(static_path, filename, sizeof(filename));
+ return static_path;
+}
+
/* The next function finds the template file and opens it, returning
** a pointer to the opened file. */
PRIVATE FILE *tplt_open(struct lemon *lemp)
{
- static char templatename[] = "lempar.c";
+ char *templatename;
char buf[1000];
FILE *in;
char *tpltname;
@@ -3530,6 +3572,7 @@
return in;
}

+ templatename = get_default_template_path("lempar.c");
cp = strrchr(lemp->filename,'.');
if( cp ){
lemon_sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename);
13 changes: 13 additions & 0 deletions recipes/lemon/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 2.8.11)
project(test_package)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()

add_custom_command(OUTPUT gram.c gram.h
COMMAND lemon -s "${PROJECT_SOURCE_DIR}/gram.y" -d"${PROJECT_BINARY_DIR}"
BYPRODUCTS gram.out
)

add_executable(${PROJECT_NAME} gram.c)
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
18 changes: 18 additions & 0 deletions recipes/lemon/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from conans import ConanFile, CMake, tools
import os


class TestPackageConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "cmake"

def build(self):
if not tools.cross_building(self.settings):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if not tools.cross_building(self.settings):
bin_path = os.path.join("bin", "test_package")
self.run(bin_path, run_environment=True)
71 changes: 71 additions & 0 deletions recipes/lemon/all/test_package/gram.y
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
%include {
#include <math.h>
#include <stdio.h>
}

%extra_argument {double *res}
%token_type {double}

res ::= expr(B). { *res = B; }
expr(A) ::= expr(B) PLUS expr(C). { A = B + C; }
expr(A) ::= expr(B) MINUS expr(C). { A = B - C; }
expr(A) ::= expr(B) TIMES expr(C). { A = B * C; }
expr(A) ::= expr(B) DIVIDE expr(C). { A = B / C;}
expr(A) ::= expr(B) MOD expr(C). { A = modf(B, &C); }
expr(A) ::= LPAREN expr(B) RPAREN. { A = B; }
expr(A) ::= VALUE(B). { A = B; }
expr(A) ::= MINUS expr(B). [UMINUS] { A = -B; }

%left PLUS MINUS.
%left TIMES DIVIDE MOD.
%right UMINUS.

%code {

#include "gram.h"

typedef struct {
int id;
double val;
} input_item_t;

static input_item_t test_input[] = {
{VALUE, 1.},
{PLUS, 0.},
{VALUE, 2.},
{PLUS, 0.},
{VALUE, 3.},
{TIMES, 0.},
{VALUE, 4.},
{TIMES, 0.},
{VALUE, 5.},
{TIMES, 0.},
{LPAREN, 0.},
{VALUE, 6.},
{MINUS, 0.},
{VALUE, 7.},
{RPAREN, 0.},
{0., 0.},
};

#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char *argv[]) {
void *pParser = ParseAlloc(malloc);
double result = -123456.;
double val;
input_item_t *input = test_input;
while (1) {
Parse(pParser, input->id, input->val, &result);
if (input->id == 0) {
break;
}
++input;
}
ParseFree(pParser, free);
printf("Result is %g.\n", result);
return 0;
}

}
3 changes: 3 additions & 0 deletions recipes/lemon/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"versions":
"3.32.3":
"folder": "all"

0 comments on commit 60bc873

Please sign in to comment.