From 7d8e406bc4a92e2e2eab772b2671dcd72ca8c202 Mon Sep 17 00:00:00 2001 From: Leo Butler Date: Tue, 12 Dec 2023 12:32:41 -0600 Subject: [PATCH] lisp/ob-C.el: add :compile-only header to compile to a named target * lisp/ob-C.el (org-babel-C-execute): The new header argument, `:compile-only', causes source and compiled binary files to be named using the `:file' header argument. When `:compile-only' is set, execution of source block ends at compilation. The naming of source and binary filenames is factored out to `org-babel-C-src/bin-file'. * lisp/ob-C.el (org-babel-C-src/bin-file): A new function that factors out the setting of source and binary filenames. It also signals an error if `:compile-only' is set, but `:file' is not. * testing/examples/ob-C-test.org: Add three example that exercise the `:compile-only' header argument, including one that causes an error. * testing/lisp/test-ob-C.el: Add three tests of the `:compile-only' header argument. New tests: ob-C/set-src+bin-file-name-{1,2,3}. Refs: https://list.orgmode.org/87fs81egk5.fsf@t14.reltub.ca/ https://list.orgmode.org/87msukbadu.fsf@localhost/ --- lisp/ob-C.el | 83 ++++++++++++++++++++-------------- testing/examples/ob-C-test.org | 26 +++++++++++ testing/lisp/test-ob-C.el | 32 +++++++++++++ 3 files changed, 108 insertions(+), 33 deletions(-) diff --git a/lisp/ob-C.el b/lisp/ob-C.el index 0278fc02a..dd772dc97 100644 --- a/lisp/ob-C.el +++ b/lisp/ob-C.el @@ -53,7 +53,8 @@ (main . :any) (flags . :any) (cmdline . :any) - (libs . :any)) + (libs . :any) + (compile-only . (nil no t yes))) "C/C++-specific header arguments.") (defconst org-babel-header-args:C++ @@ -128,17 +129,32 @@ This function is called by `org-babel-execute-src-block'." "Expand C BODY according to its header arguments PARAMS." (let ((org-babel-c-variant 'c)) (org-babel-C-expand-C body params))) +(defun org-babel-C-src/bin-file (params src? compile-only?) + "Return the src or bin filename to `org-babel-C-execute'. + +If `SRC?' is T, a file extension is added to the filename. By +default, the filename is created by `org-babel-temp-file'. If +`COMPILE-ONLY?' is T, the filename is taken from the `:file' +field in `PARAMS'; if that is NIL, an error occurs." + (let ((f (cdr (assq :file params)))) + (when (and compile-only? (null f)) + (error "Error: When COMPILE-ONLY is T or YES, output FILE needs to be set")) + (let* ((file (cond (compile-only? f) (src? "C-src-") (t "C-bin-"))) + (ext (if src? (pcase org-babel-c-variant + (`c ".c") (`cpp ".cpp") (`d ".d")) + org-babel-exeext))) + (org-babel-process-file-name + (if compile-only? (concat file ext) + (org-babel-temp-file file ext)))))) + (defun org-babel-C-execute (body params) "Execute C/C++/D BODY according to its header arguments PARAMS. This function should only be called by `org-babel-execute:C' or `org-babel-execute:C++' or `org-babel-execute:D'." - (let* ((tmp-src-file (org-babel-temp-file - "C-src-" - (pcase org-babel-c-variant - (`c ".c") (`cpp ".cpp") (`d ".d")))) - (tmp-bin-file ;not used for D - (org-babel-process-file-name - (org-babel-temp-file "C-bin-" org-babel-exeext))) + (let* ((compile-only? (let ((c (cdr (assq :compile-only params)))) + (or (string= c "t") (string= c "yes")))) + (tmp-src-file (org-babel-C-src/bin-file params t compile-only?)) + (tmp-bin-file (org-babel-C-src/bin-file params nil compile-only?)) ;not used for D (cmdline (cdr (assq :cmdline params))) (cmdline (if cmdline (concat " " cmdline) "")) (flags (cdr (assq :flags params))) @@ -170,31 +186,32 @@ This function should only be called by `org-babel-execute:C' or libs) "")) (`d nil)) ;; no separate compilation for D - (let ((results - (org-babel-eval - (pcase org-babel-c-variant - ((or `c `cpp) - (concat tmp-bin-file cmdline)) - (`d - (format "%s %s %s %s" - org-babel-D-compiler - flags - (org-babel-process-file-name tmp-src-file) - cmdline))) - ""))) - (when results - (setq results (org-remove-indentation results)) - (org-babel-reassemble-table - (org-babel-result-cond (cdr (assq :result-params params)) - results - (let ((tmp-file (org-babel-temp-file "c-"))) - (with-temp-file tmp-file (insert results)) - (org-babel-import-elisp-from-file tmp-file))) - (org-babel-pick-name - (cdr (assq :colname-names params)) (cdr (assq :colnames params))) - (org-babel-pick-name - (cdr (assq :rowname-names params)) (cdr (assq :rownames params))))) - ))) + (unless compile-only? + (let ((results + (org-babel-eval + (pcase org-babel-c-variant + ((or `c `cpp) + (concat tmp-bin-file cmdline)) + (`d + (format "%s %s %s %s" + org-babel-D-compiler + flags + (org-babel-process-file-name tmp-src-file) + cmdline))) + ""))) + (when results + (setq results (org-remove-indentation results)) + (org-babel-reassemble-table + (org-babel-result-cond (cdr (assq :result-params params)) + results + (let ((tmp-file (org-babel-temp-file "c-"))) + (with-temp-file tmp-file (insert results)) + (org-babel-import-elisp-from-file tmp-file))) + (org-babel-pick-name + (cdr (assq :colname-names params)) (cdr (assq :colnames params))) + (org-babel-pick-name + (cdr (assq :rowname-names params)) (cdr (assq :rownames params))))) + )))) (defun org-babel-C-expand-C++ (body params) "Expand C/C++ BODY with according to its header arguments PARAMS." diff --git a/testing/examples/ob-C-test.org b/testing/examples/ob-C-test.org index c7a96f665..f636aabe8 100644 --- a/testing/examples/ob-C-test.org +++ b/testing/examples/ob-C-test.org @@ -174,3 +174,29 @@ std::cout << "\"line 1\"\n"; std::cout << "\"line 2\"\n"; std::cout << "\"line 3\"\n"; #+end_src + +* File naming +:PROPERTIES: +:ID: 1a691f36-f9c1-4531-8fc0-ee7b21ef5975 +:END: + +Test that the binary file is saved in =./hello-world=. + +#+source: bin-file-1 +#+begin_src cpp :includes :results none :compile-only t :file ./hello-world +std::cout << "Hello World!\n"; +#+end_src + +Test that =yes= works, in addition to =t=. + +#+source: bin-file-2 +#+begin_src cpp :includes :results none :compile-only yes :file ./hello-world +std::cout << "Hello World!\n"; +#+end_src + +Error! + +#+source: bin-file-3 +#+begin_src cpp :includes :results none :compile-only t +std::cout << "Hello World!\n"; +#+end_src diff --git a/testing/lisp/test-ob-C.el b/testing/lisp/test-ob-C.el index c70534a51..11ec262f7 100644 --- a/testing/lisp/test-ob-C.el +++ b/testing/lisp/test-ob-C.el @@ -200,5 +200,37 @@ std::cout << (x == y); "\"line 1\"\n\"line 2\"\n\"line 3\"\n" (org-babel-execute-src-block)))))) +(ert-deftest ob-C/set-src+bin-file-name-1 () + "Test `:compile-only' header argument." + (if (executable-find org-babel-C++-compiler) + (unwind-protect + (org-test-at-id "1a691f36-f9c1-4531-8fc0-ee7b21ef5975" + (org-babel-next-src-block 1) + (org-babel-execute-src-block) + (should (file-exists-p "./hello-world")) + (should (file-exists-p "./hello-world.cpp"))) + (ignore-errors (delete-file "./hello-world")) + (ignore-errors (delete-file "./hello-world.cpp"))))) + +(ert-deftest ob-C/set-src+bin-file-name-2 () + "Test `:compile-only' header argument." + (if (executable-find org-babel-C++-compiler) + (unwind-protect + (org-test-at-id "1a691f36-f9c1-4531-8fc0-ee7b21ef5975" + (org-babel-next-src-block 2) + (org-babel-execute-src-block) + (should (file-exists-p "./hello-world")) + (should (file-exists-p "./hello-world.cpp"))) + (ignore-errors (delete-file "./hello-world")) + (ignore-errors (delete-file "./hello-world.cpp"))))) + +(ert-deftest ob-C/set-src+bin-file-name-3 () + "Test `:compile-only' header argument." + (if (executable-find org-babel-C++-compiler) + (should-error + (org-test-at-id "1a691f36-f9c1-4531-8fc0-ee7b21ef5975" + (org-babel-next-src-block 3) + (org-babel-execute-src-block))))) + (provide 'test-ob-C) ;;; test-ob-C.el ends here -- 2.42.0