On Fri, Dec 08 2023, Ihor Radchenko <yanta...@posteo.net> wrote:

> Leo Butler <leo.but...@umanitoba.ca> writes:
>
>> I submitted an imperfect patch some time ago [1] that targeted your use
>> case: allow ob-C.el to create a named binary.

> Note that I did not oppose the above behaviour when the result of
> evaluation is just compiling to :file. The problem was with compiling to
> a :file and _also_ executing it.
>
> If you want to propose a patch that will allow compile-only, I see no
> problem at all.

Ok, thank you for the clarification. I had gone on holidays after you
put up the poll and lost track.

Please see the attached patch.

Leo

From 7d8e406bc4a92e2e2eab772b2671dcd72ca8c202 Mon Sep 17 00:00:00 2001
From: Leo Butler <leo.but...@umanitoba.ca>
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....@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 <iostream> :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 <iostream> :results none :compile-only yes :file ./hello-world
+std::cout << "Hello World!\n";
+#+end_src
+
+Error!
+
+#+source: bin-file-3
+#+begin_src cpp :includes <iostream> :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

Reply via email to