Syntax-local-introduce and module boundaries

If I use syntax-local-introduce inside one module, then it works:

(define-syntax (require-macro stx)
  (syntax-local-introduce #'(require racket/math)))

(define-syntax (define-macro stx)
  (syntax-local-introduce #'(define x 10)))

(require-macro)
pi
(define-macro)
x

But if I try to use it in another module, it fails:

lib.rkt:
#lang racket/base
(require (for-syntax racket/base))
(provide require-macro define-macro)

(define-syntax (require-macro stx)
  (syntax-local-introduce #'(require racket/math)))

(define-syntax (define-macro stx)
  (syntax-local-introduce #'(define x 10)))

test.rkt:
#lang racket/base

(require "lib.rkt")

(require-macro)
pi ; this returns unbound identifier
(define-macro)
x ; this too

How to make macro introducing definition be usable through require?

The problem where is that #'(require racket/math) preserves the lexical context of the place where it occurs, which is not in the module where you wanted the bindings to be visible. The syntax-local-introduce call makes the syntax returned by the macro expansion look like it's not from a macro expansion, but that syntax is still from a different module.

You might want

(define-syntax (require-macro stx)
  (datum->syntax stx '(require racket/math)))

Using datum->syntax with stx makes the result syntax look like it came from the same place as stx, which is the use of the require-macro form.

To nitpick: it should be something like

(define-syntax (require-macro stx)
  (datum->syntax stx (list #'require 'racket/match)))

instead, because you want the local meaning of require (that is, Racket's require form), not whatever require might happen to mean at the macro use site.

This way it works, but breaks DrRacket: I see no arrow to pi and no "imported from" popup.

syntax-local-introduce variant shows "imported from racket/math".

(datum->syntax stx … #’require … stx tsx)
(define-syntax (require-macro stx)
  (datum->syntax stx '(require racket/math) stx stx stx))

and

(define-syntax (require-macro stx)
  (datum->syntax stx (list #'require 'racket/math) stx stx stx))

also don't work with DrRacket.

I've found the correct answer. It is:

(define-syntax (require-macro stx)
  (datum->syntax stx (list #'require (datum->syntax stx 'racket/math stx stx))))

Thank you all for help.

I ran into the same question of 'require' recently. And I searched for it and it brought me here. So it seems to me the (datum->syntax stx ...) is a better choice for this similar cases. Then it came to me, why do we need the syntax-local-introduce? What is the proper usage of it?