euler314 commited on
Commit
9bc509e
Β·
verified Β·
1 Parent(s): 15bbcd6

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +655 -0
app.py ADDED
@@ -0,0 +1,655 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import subprocess
4
+ import sys
5
+ import shutil
6
+ import uuid
7
+ import platform
8
+ import time
9
+ from pathlib import Path
10
+ import tempfile
11
+ import glob
12
+
13
+ def ensure_dir(dir_path):
14
+ """Ensure directory exists"""
15
+ Path(dir_path).mkdir(parents=True, exist_ok=True)
16
+
17
+ def check_dependencies():
18
+ """Check if required dependencies are available"""
19
+ missing_deps = []
20
+
21
+ # Check for patchelf
22
+ result = subprocess.run(["which", "patchelf"], capture_output=True)
23
+ if result.returncode != 0:
24
+ missing_deps.append("patchelf")
25
+
26
+ # Check for gcc
27
+ result = subprocess.run(["which", "gcc"], capture_output=True)
28
+ if result.returncode != 0:
29
+ missing_deps.append("gcc")
30
+
31
+ return missing_deps
32
+
33
+ def check_static_libpython():
34
+ """Check if static libpython is available"""
35
+ try:
36
+ # Try to find static libpython
37
+ result = subprocess.run(
38
+ [sys.executable, "-c", "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))"],
39
+ capture_output=True, text=True
40
+ )
41
+ if result.returncode == 0:
42
+ libdir = result.stdout.strip()
43
+ # Look for libpython.a files
44
+ static_libs = glob.glob(os.path.join(libdir, "libpython*.a"))
45
+ return len(static_libs) > 0
46
+ except:
47
+ pass
48
+ return False
49
+
50
+ def get_current_python_version():
51
+ """Get the current Python version for compatibility notes"""
52
+ return f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
53
+
54
+ def get_nuitka_version():
55
+ """Get the current Nuitka version to handle different command line options"""
56
+ try:
57
+ result = subprocess.run([sys.executable, "-m", "nuitka", "--version"],
58
+ capture_output=True, text=True)
59
+ if result.returncode == 0:
60
+ version_line = result.stdout.strip().split('\n')[0]
61
+ # Extract version number from output like "Nuitka 2.5.0"
62
+ version = version_line.split()[-1]
63
+ return version
64
+ return "unknown"
65
+ except:
66
+ return "unknown"
67
+
68
+ def install_system_packages(packages_content, progress=gr.Progress()):
69
+ """Install system packages from packages.txt content"""
70
+ if not packages_content.strip():
71
+ return "No system packages specified."
72
+
73
+ progress(0, desc="Starting package installation...")
74
+
75
+ # Create temporary file
76
+ fd, temp_path = tempfile.mkstemp(suffix='.txt')
77
+ try:
78
+ with os.fdopen(fd, 'w') as tmp:
79
+ tmp.write(packages_content)
80
+
81
+ # Install packages line by line
82
+ install_log = ""
83
+ failed_packages = []
84
+ successful_packages = []
85
+
86
+ lines = packages_content.strip().split('\n')
87
+ total_packages = len([line for line in lines if line.strip() and not line.strip().startswith('#')])
88
+ current_package = 0
89
+
90
+ with open(temp_path, 'r') as f:
91
+ for line in f:
92
+ line = line.strip()
93
+ # Skip empty lines and comments
94
+ if not line or line.startswith('#'):
95
+ continue
96
+
97
+ current_package += 1
98
+ progress(current_package / total_packages, desc=f"Installing: {line}")
99
+
100
+ # Try to install package
101
+ install_process = subprocess.run(
102
+ ["apt-get", "update", "-qq"],
103
+ capture_output=True,
104
+ text=True
105
+ )
106
+
107
+ install_process = subprocess.run(
108
+ ["apt-get", "install", "-y", line],
109
+ capture_output=True,
110
+ text=True
111
+ )
112
+
113
+ if install_process.returncode == 0:
114
+ successful_packages.append(line)
115
+ install_log += f"βœ… Successfully installed: {line}\n"
116
+ else:
117
+ failed_packages.append(line)
118
+ install_log += f"❌ Failed to install: {line}\n"
119
+
120
+ summary = f"""
121
+ System Packages Summary:
122
+ βœ… Successful: {', '.join(successful_packages)}
123
+ ❌ Failed: {', '.join(failed_packages)}
124
+ """
125
+ return summary + "\n" + install_log
126
+
127
+ except Exception as e:
128
+ error_msg = f"Error installing system packages: {str(e)}"
129
+ return error_msg
130
+
131
+ finally:
132
+ # Clean up
133
+ if os.path.exists(temp_path):
134
+ os.unlink(temp_path)
135
+
136
+ def find_compiled_binary(output_dir, output_filename):
137
+ """Find the compiled binary, checking different possible paths"""
138
+ # Try direct path first
139
+ direct_path = os.path.join(output_dir, output_filename)
140
+ if os.path.exists(direct_path):
141
+ return direct_path
142
+
143
+ # Try in .dist folder (standalone builds)
144
+ dist_path = os.path.join(output_dir, "user_script.dist", output_filename)
145
+ if os.path.exists(dist_path):
146
+ return dist_path
147
+
148
+ # Try using glob to find any executable
149
+ patterns = [
150
+ os.path.join(output_dir, "**", output_filename),
151
+ os.path.join(output_dir, "**", "user_script"),
152
+ os.path.join(output_dir, "**", "*.bin"),
153
+ os.path.join(output_dir, "**", "*.exe")
154
+ ]
155
+
156
+ for pattern in patterns:
157
+ matches = glob.glob(pattern, recursive=True)
158
+ if matches:
159
+ return matches[0]
160
+
161
+ return None
162
+
163
+ def compile_with_nuitka(code, requirements, packages, compilation_mode, output_extension, progress=gr.Progress()):
164
+ """Compile Python code with Nuitka"""
165
+ progress(0, desc="Starting compilation process...")
166
+
167
+ # Check Nuitka version
168
+ nuitka_version = get_nuitka_version()
169
+
170
+ # Check if static libpython is available
171
+ has_static_libpython = check_static_libpython()
172
+
173
+ # Check dependencies first
174
+ missing_deps = check_dependencies()
175
+ if missing_deps:
176
+ return f"Required dependencies are missing: {', '.join(missing_deps)}", None, None, False
177
+
178
+ # Create unique ID for this compilation
179
+ job_id = str(uuid.uuid4())
180
+ base_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "user_code")
181
+ job_dir = os.path.join(base_dir, job_id)
182
+ output_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "compiled_output", job_id)
183
+
184
+ # Create directories
185
+ ensure_dir(job_dir)
186
+ ensure_dir(output_dir)
187
+
188
+ progress(0.1, desc="Installing dependencies...")
189
+
190
+ # Install system packages if specified
191
+ packages_result = "No system packages specified."
192
+ if packages.strip():
193
+ packages_result = install_system_packages(packages, progress)
194
+
195
+ # Write code to a Python file
196
+ script_path = os.path.join(job_dir, "user_script.py")
197
+ with open(script_path, "w") as f:
198
+ f.write(code)
199
+
200
+ # Handle requirements
201
+ install_result = "No Python requirements specified."
202
+ if requirements.strip():
203
+ req_path = os.path.join(job_dir, "requirements.txt")
204
+ with open(req_path, "w") as f:
205
+ f.write(requirements)
206
+
207
+ try:
208
+ progress(0.2, desc="Installing Python requirements...")
209
+ install_process = subprocess.run(
210
+ [sys.executable, "-m", "pip", "install", "--no-cache-dir", "-r", req_path],
211
+ capture_output=True,
212
+ text=True
213
+ )
214
+
215
+ if install_process.returncode == 0:
216
+ install_result = "Python requirements installed successfully."
217
+ else:
218
+ install_result = f"Installation completed with return code: {install_process.returncode}\n{install_process.stderr}"
219
+ except Exception as e:
220
+ install_result = f"Error: {str(e)}"
221
+ return str(e), None, None, False
222
+
223
+ # Compilation
224
+ try:
225
+ progress(0.3, desc="Starting compilation...")
226
+
227
+ # Define compilation options with adaptive static linking
228
+ def build_cmd(base_cmd, use_static=False):
229
+ if use_static and has_static_libpython:
230
+ base_cmd.append("--static-libpython=yes")
231
+ return base_cmd
232
+
233
+ compile_options = {
234
+ "max_compatibility": {
235
+ "name": "Maximum Compatibility Binary",
236
+ "cmd": build_cmd([
237
+ sys.executable, "-m", "nuitka",
238
+ "--standalone",
239
+ "--onefile", # Single portable file
240
+ "--show-progress",
241
+ "--remove-output",
242
+ "--follow-imports",
243
+ "--assume-yes-for-downloads", # Auto-download missing dependencies
244
+ "--python-flag=no_site", # Reduce dependencies
245
+ script_path,
246
+ f"--output-dir={output_dir}"
247
+ ], use_static=True),
248
+ "creates_runner": False
249
+ },
250
+ "portable": {
251
+ "name": "Portable Non-Standalone",
252
+ "cmd": build_cmd([
253
+ sys.executable, "-m", "nuitka",
254
+ "--show-progress",
255
+ "--remove-output",
256
+ "--assume-yes-for-downloads",
257
+ "--python-flag=no_site",
258
+ script_path,
259
+ f"--output-dir={output_dir}"
260
+ ], use_static=True),
261
+ "creates_runner": False
262
+ },
263
+ "standalone": {
264
+ "name": "Standalone Binary",
265
+ "cmd": build_cmd([
266
+ sys.executable, "-m", "nuitka",
267
+ "--standalone",
268
+ "--onefile",
269
+ "--show-progress",
270
+ "--remove-output",
271
+ "--assume-yes-for-downloads",
272
+ "--python-flag=no_site",
273
+ script_path,
274
+ f"--output-dir={output_dir}"
275
+ ], use_static=True),
276
+ "creates_runner": False
277
+ }
278
+ }
279
+
280
+ selected_option = compile_options[compilation_mode]
281
+
282
+ # Run compilation
283
+ process = subprocess.Popen(
284
+ selected_option['cmd'],
285
+ stdout=subprocess.PIPE,
286
+ stderr=subprocess.STDOUT,
287
+ text=True,
288
+ bufsize=1,
289
+ universal_newlines=True
290
+ )
291
+
292
+ # Progress tracking
293
+ compile_output = ""
294
+ line_count = 0
295
+
296
+ # Real-time progress display
297
+ for line in iter(process.stdout.readline, ''):
298
+ compile_output += line
299
+ line_count += 1
300
+
301
+ # Update progress
302
+ progress_val = 0.3 + (min(line_count / 200, 0.69) * 0.7)
303
+ progress(progress_val, desc="Compiling...")
304
+
305
+ process.wait()
306
+
307
+ progress(0.9, desc="Finalizing...")
308
+
309
+ # Find the compiled binary
310
+ output_filename = f"user_script{output_extension}"
311
+ binary_path = find_compiled_binary(output_dir, output_filename)
312
+
313
+ # If not found with expected extension, try finding any executable
314
+ if not binary_path:
315
+ # Try common executable patterns for onefile
316
+ patterns = [
317
+ os.path.join(output_dir, "user_script"),
318
+ os.path.join(output_dir, "user_script.bin"),
319
+ os.path.join(output_dir, "**", "user_script"),
320
+ os.path.join(output_dir, "**", "*.bin"),
321
+ ]
322
+
323
+ for pattern in patterns:
324
+ matches = glob.glob(pattern, recursive=True)
325
+ if matches:
326
+ binary_path = matches[0]
327
+ break
328
+
329
+ if process.returncode == 0 and binary_path:
330
+ # Check if it's really a binary file
331
+ file_process = subprocess.run(["file", binary_path], capture_output=True, text=True)
332
+ binary_info = file_process.stdout
333
+
334
+ # Check linking type
335
+ ldd_process = subprocess.run(["ldd", binary_path], capture_output=True, text=True)
336
+ if "not a dynamic executable" in ldd_process.stderr or "statically linked" in ldd_process.stdout:
337
+ linking_info = "βœ… Statically linked - fully portable!"
338
+ else:
339
+ # Check what dynamic libraries are required
340
+ if ldd_process.returncode == 0:
341
+ libs = ldd_process.stdout.count("=>")
342
+ linking_info = f"πŸ”— Dynamically linked ({libs} libraries) - designed for maximum compatibility"
343
+ else:
344
+ linking_info = "ℹ️ Compiled binary - should work on compatible systems"
345
+
346
+ # Rename to desired extension
347
+ if output_extension in ['.bin', '.sh'] and not binary_path.endswith(output_extension):
348
+ new_binary_path = binary_path + output_extension
349
+ shutil.move(binary_path, new_binary_path)
350
+ binary_path = new_binary_path
351
+
352
+ # Make executable
353
+ os.chmod(binary_path, 0o755)
354
+
355
+ # Current Python version info
356
+ current_python = get_current_python_version()
357
+
358
+ # Add system info to result
359
+ result_summary = f"""
360
+ Compilation Details:
361
+ - Mode: {selected_option['name']}
362
+ - Nuitka Version: {nuitka_version}
363
+ - Exit Code: {process.returncode}
364
+ - Output Path: {binary_path}
365
+ - File Size: {os.path.getsize(binary_path) / 1024:.2f} KB
366
+ - Compiled with Python: {current_python}
367
+ - Static Libpython Available: {'Yes' if has_static_libpython else 'No'}
368
+ - Linking: {linking_info}
369
+
370
+ System Packages: {packages_result}
371
+ Python Requirements: {install_result}
372
+
373
+ Binary Information: {binary_info}
374
+
375
+ PORTABILITY NOTES:
376
+ - This binary was compiled with maximum compatibility settings
377
+ - Using --onefile for single-file distribution
378
+ - Added --assume-yes-for-downloads for automatic dependency resolution
379
+ - Used --python-flag=no_site to reduce system dependencies
380
+ - Should work on most compatible Linux systems
381
+ """
382
+
383
+ progress(1.0, desc="Compilation successful!")
384
+ return result_summary, binary_path, compile_output, True
385
+ else:
386
+ return f"Compilation failed.\n\nSystem Packages: {packages_result}\nPython Requirements: {install_result}", None, compile_output, False
387
+
388
+ except Exception as e:
389
+ return f"Compilation error: {str(e)}", None, f"Error: {str(e)}", False
390
+
391
+ def run_compiled_binary(binary_path):
392
+ """Run the compiled binary and return the output"""
393
+ if not binary_path or not os.path.exists(binary_path):
394
+ return "No binary available to run."
395
+
396
+ try:
397
+ # Make the binary executable
398
+ os.chmod(binary_path, 0o755)
399
+
400
+ # Run the binary with timeout
401
+ process = subprocess.run(
402
+ [binary_path],
403
+ capture_output=True,
404
+ text=True,
405
+ timeout=10
406
+ )
407
+
408
+ output = ""
409
+ if process.stdout:
410
+ output += f"[STDOUT]\n{process.stdout}\n"
411
+ if process.stderr:
412
+ output += f"[STDERR]\n{process.stderr}\n"
413
+ if process.returncode != 0:
414
+ output += f"[EXIT CODE] {process.returncode}\n"
415
+
416
+ return output if output else "No output."
417
+ except subprocess.TimeoutExpired:
418
+ return "Execution timed out after 10 seconds."
419
+ except Exception as e:
420
+ return f"Error running the binary: {str(e)}"
421
+
422
+ # Create Gradio interface
423
+ with gr.Blocks(title="Nuitka Python Compiler", theme=gr.themes.Soft()) as app:
424
+ gr.Markdown("# πŸš€ Nuitka Python Compiler (Smart Compilation)")
425
+ gr.Markdown("Convert your Python code into portable executables using Nuitka with smart compatibility detection.")
426
+
427
+ # Check environment status
428
+ has_static = check_static_libpython()
429
+ missing_deps = check_dependencies()
430
+
431
+ if has_static:
432
+ gr.Info("🎯 Static Libpython Available! Maximum portability enabled.")
433
+ else:
434
+ gr.Info("πŸ”§ Using alternative portable options. Static libpython not available.")
435
+
436
+ if missing_deps:
437
+ gr.Warning(f"⚠️ Missing dependencies: {', '.join(missing_deps)}")
438
+ else:
439
+ gr.Info("βœ… All required dependencies available!")
440
+
441
+ with gr.Tabs():
442
+ with gr.TabItem("πŸ”§ Compiler"):
443
+ with gr.Row():
444
+ with gr.Column(scale=2):
445
+ code_input = gr.Code(
446
+ value="""# Your Python code here
447
+ print('Hello from compiled Python!')
448
+ print('This is a smart-compiled binary!')
449
+
450
+ # This will work with automatic compatibility detection
451
+ import os, sys
452
+ print(f'Running from: {os.getcwd()}')
453
+ print(f'Python executable: {sys.executable}')
454
+ print('Compilation was optimized for your environment!')""",
455
+ language="python",
456
+ label="Your Python Code",
457
+ lines=20
458
+ )
459
+
460
+ with gr.Column(scale=1):
461
+ with gr.Tabs():
462
+ with gr.TabItem("Python Requirements"):
463
+ requirements_input = gr.Textbox(
464
+ placeholder="""# Add your Python dependencies here
465
+ # Example:
466
+ # numpy==1.24.0
467
+ # pandas==2.0.0
468
+ # requests>=2.28.0""",
469
+ lines=8,
470
+ label="requirements.txt content"
471
+ )
472
+
473
+ with gr.TabItem("System Packages"):
474
+ packages_input = gr.Textbox(
475
+ placeholder="""# Add system packages here (one per line)
476
+ # Example:
477
+ # build-essential
478
+ # libssl-dev
479
+ # ffmpeg
480
+ # imagemagick""",
481
+ lines=8,
482
+ label="packages.txt content"
483
+ )
484
+
485
+ compilation_mode = gr.Dropdown(
486
+ choices=[
487
+ ("max_compatibility", "Maximum Compatibility (Recommended)"),
488
+ ("portable", "Portable Binary"),
489
+ ("standalone", "Standalone Binary")
490
+ ],
491
+ value="max_compatibility",
492
+ label="Compilation Mode"
493
+ )
494
+
495
+ output_extension = gr.Dropdown(
496
+ choices=[".bin", ".sh"],
497
+ value=".bin",
498
+ label="Output File Extension"
499
+ )
500
+
501
+ gr.Info(f"πŸ“ Compiling with Python {get_current_python_version()}")
502
+ if check_static_libpython():
503
+ gr.Success("πŸ”— Static libpython will be used!")
504
+ else:
505
+ gr.Info("πŸ”§ Using portable compilation flags")
506
+
507
+ compile_btn = gr.Button("πŸš€ Compile with Nuitka", variant="primary")
508
+
509
+ # Results section
510
+ result_summary = gr.Textbox(label="Compilation Results", lines=10, visible=False)
511
+ compile_logs = gr.Textbox(label="Compilation Logs", lines=10, visible=False)
512
+ download_file = gr.File(label="Download Compiled Binary", visible=False)
513
+
514
+ # Test run section
515
+ with gr.Row():
516
+ run_btn = gr.Button("πŸ§ͺ Test Run", visible=False)
517
+ run_output = gr.Textbox(label="Execution Output", lines=8, visible=False)
518
+
519
+ # Variables to store state
520
+ current_binary_path = gr.State(None)
521
+ compilation_success = gr.State(False)
522
+
523
+ def handle_compilation(code, requirements, packages, mode, extension, progress=gr.Progress()):
524
+ summary, binary_path, logs, success = compile_with_nuitka(
525
+ code, requirements, packages, mode, extension, progress
526
+ )
527
+
528
+ if success and binary_path:
529
+ # Create download file
530
+ download_filename = f"compiled_program{extension}"
531
+ download_path = os.path.join(os.path.dirname(binary_path), download_filename)
532
+ shutil.copy2(binary_path, download_path)
533
+
534
+ return (
535
+ gr.update(value=summary, visible=True), # result_summary
536
+ gr.update(value=logs, visible=True), # compile_logs
537
+ gr.update(value=download_path, visible=True), # download_file
538
+ gr.update(visible=True), # run_btn
539
+ binary_path, # current_binary_path state
540
+ True # compilation_success state
541
+ )
542
+ else:
543
+ return (
544
+ gr.update(value=summary, visible=True), # result_summary
545
+ gr.update(value=logs, visible=True), # compile_logs
546
+ gr.update(visible=False), # download_file
547
+ gr.update(visible=False), # run_btn
548
+ None, # current_binary_path state
549
+ False # compilation_success state
550
+ )
551
+
552
+ def handle_run(binary_path):
553
+ if binary_path:
554
+ output = run_compiled_binary(binary_path)
555
+ return gr.update(value=output, visible=True)
556
+ else:
557
+ return gr.update(value="No binary available to run.", visible=True)
558
+
559
+ compile_btn.click(
560
+ handle_compilation,
561
+ inputs=[code_input, requirements_input, packages_input, compilation_mode, output_extension],
562
+ outputs=[result_summary, compile_logs, download_file, run_btn, current_binary_path, compilation_success]
563
+ )
564
+
565
+ run_btn.click(
566
+ handle_run,
567
+ inputs=[current_binary_path],
568
+ outputs=[run_output]
569
+ )
570
+
571
+ with gr.TabItem("πŸ“– How to Use"):
572
+ gr.Markdown("""
573
+ ## 🎯 Smart Compilation
574
+
575
+ **Automatic Environment Detection**
576
+
577
+ This app automatically detects your Python environment and chooses the best compilation strategy:
578
+ - Uses static libpython if available (maximum portability)
579
+ - Falls back to highly portable alternatives if not
580
+ - Automatically handles missing dependencies
581
+ - Optimizes for your specific environment
582
+
583
+ ## πŸ“‹ General Instructions
584
+
585
+ ```bash
586
+ # Download the compiled binary
587
+ # Method 1: Direct run (if static libpython was used)
588
+ chmod +x compiled_program.bin
589
+ ./compiled_program.bin
590
+
591
+ # Method 2: Copy to Linux filesystem first (recommended for WSL)
592
+ cp /mnt/c/Users/username/Downloads/compiled_program.bin ~/
593
+ cd ~
594
+ chmod +x compiled_program.bin
595
+ ./compiled_program.bin
596
+ ```
597
+
598
+ ## πŸ“Š Environment Types
599
+
600
+ | Environment | Portability | Requirements | Best For |
601
+ |-------------|-------------|--------------|----------|
602
+ | Static Libpython | Maximum | None | Any Linux system |
603
+ | Non-Static Libpython | High | Compatible system | Similar environments |
604
+ """)
605
+
606
+ with gr.TabItem("ℹ️ About"):
607
+ gr.Markdown(f"""
608
+ ## 🧠 Smart Compilation Technology
609
+
610
+ **How it works:**
611
+
612
+ 1. **Environment Detection**: Checks if static libpython is available
613
+ 2. **Adaptive Options**: Uses the best available compilation flags
614
+ 3. **Fallback Strategy**: Ensures compilation succeeds even without static linking
615
+ 4. **Automatic Dependencies**: Resolves missing dependencies automatically
616
+
617
+ This approach maximizes compatibility across different Python environments.
618
+
619
+ ## βœ… What This Solves
620
+
621
+ **Problems addressed:**
622
+
623
+ - Static libpython not available error
624
+ - Python version mismatches
625
+ - WSL compatibility issues
626
+ - Dependency resolution
627
+ - Cross-environment portability
628
+
629
+ ## ☁️ Current Environment Status
630
+
631
+ ```
632
+ Python Version: {get_current_python_version()}
633
+ Nuitka Version: {get_nuitka_version()}
634
+ Platform: {platform.platform()}
635
+ Architecture: {platform.architecture()[0]}
636
+ Machine: {platform.machine()}
637
+ Static Libpython: {'βœ… Available' if check_static_libpython() else '❌ Not Available'}
638
+ ```
639
+
640
+ ## πŸ“‹ Best Practices
641
+
642
+ **Recommendations:**
643
+
644
+ 1. Always use "Maximum Compatibility" mode
645
+ 2. Copy binaries to Linux filesystem in WSL
646
+ 3. Test the binary in the target environment
647
+ 4. Let the app automatically choose the best settings
648
+ 5. Check the compilation details for specific optimization used
649
+ """)
650
+
651
+ gr.Markdown("---")
652
+ gr.Markdown("πŸ€– Created by Claude 3.7 Sonnet | πŸš€ Powered by Nuitka with Smart Compilation")
653
+
654
+ if __name__ == "__main__":
655
+ app.launch(share=True)