Recent

Author Topic: FPC 3.2.2 - how to fix export error ?  (Read 1375 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 17368
  • Ceterum censeo Trump esse delendam
Re: FPC 3.2.2 - how to fix export error ?
« Reply #15 on: May 09, 2025, 11:00:57 am »
It is much easier to compile with -a and examine the .s file.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12300
  • FPC developer.
Re: FPC 3.2.2 - how to fix export error ?
« Reply #16 on: May 09, 2025, 11:03:06 am »
It does not matter what your preference is. If library boundaries are involved special care needs to be taken for both AnsiString and UnicodeString so that both the library and the main application use the same memory manager otherwise this will end in problems. The same is also true for any other allocations including PChar if they're allocated in one binary and released in the other, but there you have manual allocations/deallocations in comparison to the managed string types.

Isn't exporting Non function symbols from DLLs supported at all? It is a bit a grey area afaik

paule32

  • Hero Member
  • *****
  • Posts: 553
  • One in all. But, not all in one.
Re: FPC 3.2.2 - how to fix export error ?
« Reply #17 on: May 09, 2025, 11:09:27 am »
it is working under Windows 10/11 that fpc can export and import Symbols on two different ways:
- either you use win32api like LoadLibrary
- either you use:

Code: Pascal  [Select][+][-]
  1. function foo: String; export;
  2. begin
  3. ...
  4. end;
  5.  
  6. function foo: String; external 'dllname.dll';
  7.  
  8. exports
  9.   foo name 'foo';  // 'foo' instead mangled name
  10.  

or the second option is:  LoadLibrary and GetProcAddress

But attention: if you write on Library, you get into trouble if you mix export and import code together.
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

Thaddy

  • Hero Member
  • *****
  • Posts: 17368
  • Ceterum censeo Trump esse delendam
Re: FPC 3.2.2 - how to fix export error ?
« Reply #18 on: May 09, 2025, 11:39:09 am »
The same is also true for any other allocations including PChar if they're allocated in one binary and released in the other, but there you have manual allocations/deallocations in comparison to the managed string types.
That is not true for literals declared as PChar as per my demo. Nothing to de-allocate/release. But it often more convenient to copy it over to a string type using SetString anyway. Don't tell me I am wrong again  ;D
« Last Edit: May 09, 2025, 11:42:21 am by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

paule32

  • Hero Member
  • *****
  • Posts: 553
  • One in all. But, not all in one.
Re: FPC 3.2.2 - how to fix export error ?
« Reply #19 on: May 09, 2025, 12:13:38 pm »
Does someone know, how I can create a DLL and/or EXE File by only using the generated .o and .a Files ?
I am intressting in what or how FPC does internaly doing to create a EXE.

Because FPC can create .S (Assembler) Files, which can be assembly with the desired Assembler Tool.
In my case the favourite is NASM.EXE in 64-Bit mode, which can produce Windows COFF Files.

I had let the gcc.exe a try - but I fail.
Beause many many ... unresolved References.

I must write there, that I only use my and fibonacci's .o generated Files.

BTW: in the Context above, I get the error: "ld: error: 0-bit reloc in dll"
« Last Edit: May 09, 2025, 12:16:19 pm by paule32 »
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

Fibonacci

  • Hero Member
  • *****
  • Posts: 786
  • Internal Error Hunter
Re: FPC 3.2.2 - how to fix export error ?
« Reply #20 on: May 09, 2025, 12:32:39 pm »
Does someone know, how I can create a DLL and/or EXE File by only using the generated .o and .a Files ?
I am intressting in what or how FPC does internaly doing to create a EXE.

Project Options -> Compiler Options -> Custom Options, click on "All options...", search for "external". There are "-Xe", "-st", "-sh". Use "-sh" or "-st", FPC will generate a script. Inside the script there are all .o files used and more interesting things. You can generate ".s" file first, edit it, compile to ".o", generate a script, edit it, then link.
« Last Edit: May 09, 2025, 12:34:39 pm by Fibonacci »

paule32

  • Hero Member
  • *****
  • Posts: 553
  • One in all. But, not all in one.
Re: FPC 3.2.2 - how to fix export error ?
« Reply #21 on: May 09, 2025, 04:13:20 pm »
Thanks fibodev for the reply.
I prompted this request with a new Tool, that catch FPC and NASM - see attachment.

The source is a Python Script:

Code: Pascal  [Select][+][-]
  1. # ---------------------------------------------------------------------------------------
  2. # Copyright(c) 2025 @paule32 & @fibodev
  3. # ---------------------------------------------------------------------------------------
  4. import sys
  5. import os
  6. import subprocess
  7. from PyQt5.QtWidgets import (
  8.     QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QComboBox,
  9.     QFileDialog, QTextEdit, QLineEdit, QSplitter,
  10.     QMessageBox, QPlainTextEdit
  11. )
  12. from PyQt5.QtGui  import QPainter, QColor, QFont, QTextFormat
  13. from PyQt5.QtCore import Qt, QRect, QSize
  14.  
  15. # CUSTOMIZED THE TWO ITEMS !!!
  16. FPC = "C:\\fpcupdeluxe\\fpc\\bin\\x86_64-win64\\fpc.exe"
  17. ASM = "T:\\msys64\\mingw64\\bin\\nasm.exe"
  18.  
  19. MAC_EXPORT = "-dDLLEXPORT"
  20. MAC_LANG   = "-dLANGDEU"
  21.  
  22. class LineNumberArea(QWidget):
  23.     def __init__(self, editor):
  24.         super().__init__(editor)
  25.         self.code_editor = editor
  26.  
  27.     def sizeHint(self):
  28.         return QSize(self.code_editor.line_number_area_width(), 0)
  29.  
  30.     def paintEvent(self, event):
  31.         self.code_editor.line_number_area_paint_event(event)
  32.  
  33.  
  34. class CodeEditor(QPlainTextEdit):
  35.     def __init__(self, parent=None):
  36.         super().__init__(parent)
  37.         self.lineNumberArea = LineNumberArea(self)
  38.  
  39.         self.blockCountChanged.connect(self.update_line_number_area_width)
  40.         self.updateRequest.connect(self.update_line_number_area)
  41.         self.cursorPositionChanged.connect(self.highlight_current_line)
  42.  
  43.         self.update_line_number_area_width(0)
  44.         self.highlight_current_line()
  45.  
  46.     def line_number_area_width(self):
  47.         digits = len(str(self.blockCount()))
  48.         space = 3 + self.fontMetrics().horizontalAdvance('9') * digits
  49.         return space
  50.  
  51.     def update_line_number_area_width(self, _):
  52.         self.setViewportMargins(self.line_number_area_width(), 0, 0, 0)
  53.  
  54.     def update_line_number_area(self, rect, dy):
  55.         if dy:
  56.             self.lineNumberArea.scroll(0, dy)
  57.         else:
  58.             self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height())
  59.  
  60.         if rect.contains(self.viewport().rect()):
  61.             self.update_line_number_area_width(0)
  62.  
  63.     def resizeEvent(self, event):
  64.         super().resizeEvent(event)
  65.         cr = self.contentsRect()
  66.         self.lineNumberArea.setGeometry(QRect(cr.left(), cr.top(), self.line_number_area_width(), cr.height()))
  67.  
  68.     def line_number_area_paint_event(self, event):
  69.         painter = QPainter(self.lineNumberArea)
  70.         painter.fillRect(event.rect(), QColor(240, 240, 240))
  71.  
  72.         block = self.firstVisibleBlock()
  73.         block_number = block.blockNumber()
  74.         top = int(self.blockBoundingGeometry(block).translated(self.contentOffset()).top())
  75.         bottom = top + int(self.blockBoundingRect(block).height())
  76.  
  77.         while block.isValid() and top <= event.rect().bottom():
  78.             if block.isVisible() and bottom >= event.rect().top():
  79.                 number = str(block_number + 1)
  80.                 painter.setPen(Qt.black)
  81.                 painter.drawText(0, top, self.lineNumberArea.width() - 5, self.fontMetrics().height(),
  82.                                  Qt.AlignRight, number)
  83.  
  84.             block = block.next()
  85.             top = bottom
  86.             bottom = top + int(self.blockBoundingRect(block).height())
  87.             block_number += 1
  88.  
  89.     def highlight_current_line(self):
  90.         extraSelections = []
  91.  
  92.         if not self.isReadOnly():
  93.             selection = QTextEdit.ExtraSelection()
  94.             lineColor = QColor(220, 240, 255)
  95.             selection.format.setBackground(lineColor)
  96.             selection.format.setProperty(QTextFormat.FullWidthSelection, True)
  97.             #selection.format.setProperty(QTextEdit.ExtraSelection.FullWidthSelection, True)
  98.             selection.cursor = self.textCursor()
  99.             selection.cursor.clearSelection()
  100.             extraSelections.append(selection)
  101.  
  102.         self.setExtraSelections(extraSelections)
  103.  
  104. class PascalAssemblerGUI(QWidget):
  105.     def __init__(self):
  106.         super().__init__()
  107.         self.setWindowTitle("Pascal zu Assembler GUI")
  108.         self.resize(1200, 800)
  109.         self.current_dir = ""
  110.         self.files = []
  111.  
  112.         self.init_ui()
  113.  
  114.     def init_ui(self):
  115.         main_layout = QVBoxLayout()
  116.  
  117.         # Top: ComboBox + Button
  118.         top_layout = QHBoxLayout()
  119.         self.combo_box = QComboBox()
  120.         self.combo_box.currentIndexChanged.connect(self.load_pascal_file)
  121.         top_layout.addWidget(self.combo_box)
  122.  
  123.         self.btn_open_dir = QPushButton("select directory")
  124.         self.btn_open_dir.clicked.connect(self.select_directory)
  125.         top_layout.addWidget(self.btn_open_dir)
  126.  
  127.         main_layout.addLayout(top_layout)
  128.  
  129.         # Extra FPC Arguments
  130.         self.args_line = QLineEdit("-dDLLEXPORT -dLANGDEU")
  131.         main_layout.addWidget(self.args_line)
  132.  
  133.         # Split Editor: Pascal | Assembler
  134.         self.editor_pascal = CodeEditor(self)
  135.         self.editor_asm = CodeEditor(self)
  136.  
  137.         splitter = QSplitter(Qt.Horizontal)
  138.         splitter.addWidget(self.editor_pascal)
  139.         splitter.addWidget(self.editor_asm)
  140.         main_layout.addWidget(splitter)
  141.  
  142.         # Bottom Buttons
  143.         bottom_layout = QHBoxLayout()
  144.  
  145.         self.btn_compile_fpc = QPushButton("Compile with FPC")
  146.         self.btn_compile_fpc.clicked.connect(self.compile_fpc)
  147.         bottom_layout.addWidget(self.btn_compile_fpc)
  148.  
  149.         self.btn_compile_nasm = QPushButton("compile with NASM")
  150.         self.btn_compile_nasm.clicked.connect(self.compile_nasm)
  151.         bottom_layout.addWidget(self.btn_compile_nasm)
  152.  
  153.         main_layout.addLayout(bottom_layout)
  154.         self.setLayout(main_layout)
  155.  
  156.     def select_directory(self):
  157.         directory = QFileDialog.getExistingDirectory(self, "Select Directory")
  158.         if directory:
  159.             self.current_dir = directory
  160.             self.files = [f for f in os.listdir(directory)
  161.                           if f.endswith((".pas", ".pp", ".inc"))]
  162.             self.combo_box.clear()
  163.             self.combo_box.addItems(self.files)
  164.  
  165.     def load_pascal_file(self):
  166.         file_name = self.combo_box.currentText()
  167.         if file_name:
  168.             path = os.path.join(self.current_dir, file_name)
  169.             with open(path, "r", encoding="utf-8") as f:
  170.                 content = f.read()
  171.                 self.editor_pascal.setPlainText(content)
  172.             self.editor_asm.clear()
  173.  
  174.     def compile_fpc(self):
  175.         file_name = self.combo_box.currentText()
  176.         if not file_name:
  177.             return
  178.  
  179.         name_path = self.current_dir
  180.         full_path = os.path.join(self.current_dir, file_name)
  181.         full_path = full_path.replace('/','\\')
  182.        
  183.         #args = self.args_line.text()
  184.        
  185.         result = subprocess.run(
  186.         [FPC, MAC_EXPORT, MAC_LANG,"-n","-B","-O3","-Os","-a","-al","-Anasmwin64","-CD","-FE",
  187.         name_path, " ", full_path ],
  188.         stdout=subprocess.PIPE,
  189.         stderr=subprocess.PIPE,
  190.         text=True)
  191.         if result.returncode == 0:
  192.             QMessageBox.information(self, "Success", "Assembly file written.")
  193.         else:
  194.             QMessageBox.critical(self, "Failed", "Error: " + result.stderr + result.stdout)
  195.        
  196.         # Nach .s-Datei suchen
  197.         base_name = os.path.splitext(file_name)[0]
  198.         asm_file = os.path.join(self.current_dir, base_name + ".s")
  199.         asm_file = asm_file.replace('/','\\')
  200.        
  201.         if os.path.exists(asm_file):
  202.             with open(asm_file, "r", encoding="utf-8") as f:
  203.                 asm_content = f.read()
  204.                 self.editor_asm.setPlainText(asm_content)
  205.  
  206.     def compile_nasm(self):
  207.         # Beispielhafter NASM-Befehl, passe dies ggf. an
  208.         file_name = self.combo_box.currentText()
  209.         base_name = os.path.splitext(file_name)[0]
  210.         asm_file = os.path.join(self.current_dir, base_name + ".s")
  211.         asm_file = asm_file.replace('/','\\')
  212.  
  213.         if not os.path.exists(asm_file):
  214.             print("assembly file missing")
  215.             return
  216.  
  217.         output_file = os.path.join(self.current_dir, base_name + ".obj")
  218.         output_file = output_file.replace('/','\\')
  219.        
  220.         #cmd = (ASM + " -fwin64 " + asm_file + " -o " + output_file)
  221.        
  222.         result = subprocess.run(
  223.         [ASM, "-fwin64", asm_file, "-o", output_file],
  224.         stdout=subprocess.PIPE,
  225.         stderr=subprocess.PIPE,
  226.         text=True)
  227.         if result.returncode == 0:
  228.             QMessageBox.information(self, "Success", "Object file written.")
  229.         else:
  230.             QMessageBox.critical(self, "Failed", "Error: could not write object file.")
  231.  
  232. if __name__ == "__main__":
  233.     app = QApplication(sys.argv)
  234.     gui = PascalAssemblerGUI()
  235.     gui.show()
  236.     sys.exit(app.exec_())
  237.  
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6033
  • Compiler Developer
Re: FPC 3.2.2 - how to fix export error ?
« Reply #22 on: May 11, 2025, 04:10:33 pm »
I have written a Python Script, that dump the Symbols of .ppu, and .o Files.

Please note that ppudump supports output in JSON (-Fj) or XML (-Fx) format for easier machine readability.

 

TinyPortal © 2005-2018